Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,6 @@ jobs:
version: npx tsx .github/changeset-version.ts
publish: npx tsx .github/changeset-publish.ts
env:
GITHUB_TOKEN: ${{ secrets.SANDBOX_GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unexplained token change: Why switch from SANDBOX_GITHUB_TOKEN to default GITHUB_TOKEN?

Questions:

  1. Does default token have sufficient permissions for changesets action?
  2. Was SANDBOX_GITHUB_TOKEN a GitHub App token with broader permissions?
  3. Why bundle this with docs sync instead of separate PR?

If the default token lacks permissions (e.g., for creating "Version Packages" PR), releases will fail. This should be tested separately.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change tokens? If SANDBOX_GITHUB_TOKEN had elevated permissions (e.g., to trigger workflows), default GITHUB_TOKEN will break releases. This change seems unrelated to docs sync.

NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
NPM_PUBLISH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
237 changes: 237 additions & 0 deletions .github/workflows/sync-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
name: Documentation Sync with Claude Code

on:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing path filter: This will run on every PR, including test-only changes, workflow updates, etc. This wastes Actions minutes and Anthropic API credits.

Recommend adding path filtering like pkg-pr-new.yml does:

on:
  pull_request:
    types: [opened, synchronize, edited]
    paths:
      - 'docs/**'
      - 'packages/sandbox/src/**'
      - 'examples/**'
      - '!**/*.test.ts'
      - '!**/tests/**'

Or at minimum, exclude workflow changes:

paths:
  - '**'
  - '!.github/workflows/**'

pull_request:
types: [opened, synchronize, edited]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing path filter means this runs on every PR (tests, workflows, etc). Add paths filter to only trigger on documentation-relevant changes.


jobs:
sync-docs:
runs-on: ubuntu-latest
if: "!startsWith(github.event.pull_request.title, 'Version Packages')"
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
owner: cloudflare

- name: Checkout source repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Get changed files
id: changed-files
run: |
git fetch origin ${{ github.event.pull_request.base.ref }}
CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }}...HEAD | tr '\n' ',' | sed 's/,$//')
echo "changed_files=$CHANGED_FILES" >> $GITHUB_OUTPUT
echo "Changed files: $CHANGED_FILES"
- name: Checkout cloudflare-docs repository
uses: actions/checkout@v4
with:
repository: cloudflare/cloudflare-docs
token: ${{ steps.generate-token.outputs.token }}
path: cloudflare-docs

- name: Create branch in cloudflare-docs
run: |
cd cloudflare-docs
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b sync-docs-pr-${{ github.event.pull_request.number }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch collision risk: If a previous run failed, this branch may already exist and git checkout -b will fail.

Recommend making this idempotent:

# Delete local/remote branch if exists
git branch -D sync-docs-pr-${{ github.event.pull_request.number }} 2>/dev/null || true
git push origin --delete sync-docs-pr-${{ github.event.pull_request.number }} 2>/dev/null || true

# Create fresh branch
git checkout -b sync-docs-pr-${{ github.event.pull_request.number }}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch creation fails on PR updates because branch already exists from first run. Make idempotent:

git fetch origin
git branch -D sync-docs-pr-${{ github.event.pull_request.number }} 2>/dev/null || true
git push origin --delete sync-docs-pr-${{ github.event.pull_request.number }} 2>/dev/null || true
git checkout -b sync-docs-pr-${{ github.event.pull_request.number }}

- name: Create prompt for Claude Code
id: create-prompt
run: |
# Store PR metadata in environment variables to avoid shell escaping issues
PR_NUMBER="${{ github.event.pull_request.number }}"
PR_TITLE="${{ github.event.pull_request.title }}"
PR_URL="https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
cat > /tmp/claude_prompt.md << EOF
# Intelligent Documentation Sync Task
## Context
- **Source Repository:** ${{ github.repository }}
- **Original PR Number:** ${PR_NUMBER}
- **Original PR Title:** ${PR_TITLE}
- **Original PR URL:** ${PR_URL}
- **Changed Files:** ${{ steps.changed-files.outputs.changed_files }}
- **PR Description:**
${{ github.event.pull_request.body }}
⚠️ **IMPORTANT**: All PR metadata above is the ONLY source of truth. Use these values EXACTLY as written.
DO NOT fetch PR title/URL from GitHub APIs.
## Your Task: Evaluate and Act
**First, gather the information you need:**
1. Review the list of changed files above
2. Use \`gh pr diff ${PR_NUMBER}\` to see the full diff for this PR
3. Use the Read tool to examine specific files if needed
You have access to two repositories:
1. The current directory (our main repo at ${{ github.repository }})
2. ./cloudflare-docs (already cloned with branch sync-docs-pr-${{ github.event.pull_request.number }} checked out)
**Step 1: Evaluate if Documentation Sync is Needed**
Review the changes and determine if they require documentation updates in cloudflare-docs:
- **ALWAYS sync if ANY of these are true:**
- Documentation files in docs/ were directly changed (even if other non-doc files also changed)
- New public API features or functions were added
- Breaking changes that affect user-facing behavior
- New configuration options or environment variables
- New examples or usage patterns that should be documented
- Bug fixes that clarify documented behavior
- **DO NOT sync ONLY if ALL changes are:**
- Only internal code refactoring with no behavior changes
- Test-only changes
- CI/workflow changes (UNLESS docs/ files also changed)
- Minor typo fixes in code comments
- Internal dependency updates with no API changes
**IMPORTANT**: If this PR includes ANY changes to files in the docs/ directory, you MUST proceed with the sync, even if the PR also includes other types of changes like workflow updates.
**Step 2: If Documentation Sync is Needed**
If you determine documentation updates are required, YOU MUST COMPLETE ALL STEPS:
1. Navigate to ./cloudflare-docs (already cloned, branch sync-docs-pr-${PR_NUMBER} checked out)
2. Adapt changes for cloudflare-docs repository structure and style
3. Create or update the appropriate markdown files
4. Ensure content follows cloudflare-docs conventions
5. **CRITICAL - Commit changes:**
Run exactly: `cd cloudflare-docs && git add . && git commit -m "Sync docs from cloudflare/sandbox-sdk#${PR_NUMBER}: ${PR_TITLE}"`
6. **CRITICAL - Push to remote:**
Run exactly: `cd cloudflare-docs && git push origin sync-docs-pr-${PR_NUMBER}`
7. **CRITICAL - Create or update PR in cloudflare-docs:**
⚠️ **CRITICAL**: Use the exact PR_NUMBER, PR_TITLE, and PR_URL values from the Context section above.
Copy and run this EXACT script (replace PLACEHOLDER values with actual values from Context):
```bash
# Set variables from Context section above
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder replacement is fragile. If Claude fails to replace PLACEHOLDER values, commands silently fail with cryptic errors. Consider passing values via environment variables instead.

PR_NUMBER="PLACEHOLDER_PR_NUMBER"
PR_TITLE="PLACEHOLDER_PR_TITLE"
PR_URL="PLACEHOLDER_PR_URL"
# Check if PR already exists
EXISTING_PR=$(gh pr list --repo cloudflare/cloudflare-docs --head sync-docs-pr-${PR_NUMBER} --json number --jq '.[0].number')
# Create PR title and body
PR_TITLE_TEXT="📚 Sync docs from cloudflare/sandbox-sdk#${PR_NUMBER}: ${PR_TITLE}"
PR_BODY_TEXT="Syncs documentation changes from [cloudflare/sandbox-sdk#${PR_NUMBER}](${PR_URL}): **${PR_TITLE}**"
if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then
# Update existing PR
echo "Updating existing PR #$EXISTING_PR"
gh pr edit $EXISTING_PR --repo cloudflare/cloudflare-docs --title "$PR_TITLE_TEXT" --body "$PR_BODY_TEXT"
else
# Create new PR
echo "Creating new PR"
gh pr create --repo cloudflare/cloudflare-docs --base main --head sync-docs-pr-${PR_NUMBER} --title "$PR_TITLE_TEXT" --body "$PR_BODY_TEXT"
fi
```
⚠️ THE TASK IS NOT COMPLETE UNTIL ALL 7 STEPS ARE DONE. Do not stop after editing files.
## Documentation Writing Guidelines (Diátaxis Framework)
When writing the documentation content, adapt your approach based on what changed:
**For a single function/method:**
- **Reference**: Technical description - signature, parameters, return types, behavior
- **Example**: Concise code snippet showing usage in context
- **Use cases**: Brief bullets on when/why to use it (if not obvious)
- **DO NOT** create separate "how-to" sections - integrate examples into the reference
**For new features/workflows (multiple related functions):**
- **Reference**: Complete API docs for all functions
- **How-to guide**: Step-by-step guide for real-world tasks
- **Explanation**: Architecture, design decisions, alternatives
**For breaking changes:**
- **Reference**: Updated API documentation
- **How-to**: Migration guide (before/after)
- **Explanation**: Why changed, implications
**Key principles:**
- Single functions = reference + example (concise)
- Multi-step workflows = separate how-to guides
- Keep reference neutral and factual
- Don't overexplain simple functions
## Cloudflare Docs Style Requirements
**CRITICAL**: Follow all rules from the [Cloudflare Style Guide](https://developers.cloudflare.com/style-guide/) and these specific requirements:
**Grammar & Formatting:**
- Do not use contractions, exclamation marks, or non-standard quotes like \`''""\`
- Fix common spelling errors, specifically misspellings of "wrangler"
- Remove whitespace characters from the end of lines
- Remove duplicate words
- Do not use HTML for ordered lists
**Links:**
- Use full relative links (\`/sandbox-sdk/configuration/\`) instead of full URLs, local dev links, or dot notation
- Always use trailing slashes for links without anchors
- Use meaningful link words (page titles) - avoid "here", "this page", "read more"
- Add cross-links to relevant documentation pages where appropriate
**Components (MUST USE):**
- All components need to be imported below frontmatter: \`import { ComponentName } from "~/components";\`
- **WranglerConfig component**: Replace \`toml\` or \`json\` code blocks showing Wrangler configuration with the [\`WranglerConfig\` component](https://developers.cloudflare.com/style-guide/components/wrangler-config/). This is CRITICAL - always use this component for wrangler.toml/wrangler.jsonc examples.
- **DashButton component**: Replace \`https://dash.cloudflare.com\` in steps with the [\`DashButton\` component](https://developers.cloudflare.com/style-guide/components/dash-button/)
- **APIRequest component**: Replace \`sh\` code blocks with API requests to \`https://api.cloudflare.com\` with the [\`APIRequest\` component](https://developers.cloudflare.com/style-guide/components/api-request/)
- **FileTree component**: Replace \`txt\` blocks showing file trees with the [\`FileTree\` component](https://developers.cloudflare.com/style-guide/components/file-tree/)
- **PackageManagers component**: Replace \`sh\` blocks with npm commands using the [\`PackageManagers\` component](https://developers.cloudflare.com/style-guide/components/package-managers/)
- **TypeScriptExample component**: Replace \`ts\`/\`typescript\` code blocks with the [\`TypeScriptExample\` component](https://developers.cloudflare.com/style-guide/components/typescript-example/) (except in step-by-step TypeScript-specific tutorials)
**JSX & Partials:**
- When using JSX fragments for conditional rendering, use props variable to account for reusability
- Only use \`<Markdown />\` component in JSX conditionals, and only if needed
- Do not duplicate content in ternary/binary conditions
- For variables in links, use HTML instead of Markdown
**Step 3: Provide Clear Output**
Clearly state your decision:
- If syncing: Explain what documentation changes you're making and why
- If not syncing: Explain why documentation updates aren't needed for this PR
## Important Notes
- Use the GH_TOKEN environment variable for authentication with gh CLI
- Adapt paths, links, and references as needed for cloudflare-docs structure
- Follow existing patterns in the cloudflare-docs repository
- **DEFAULT TO SYNCING**: When in doubt about whether changes warrant a sync, ALWAYS create the sync PR for human review. It's better to create an unnecessary PR than to miss important documentation updates.
Begin your evaluation now.
EOF
echo "prompt<<PROMPT_EOF" >> $GITHUB_OUTPUT
cat /tmp/claude_prompt.md >> $GITHUB_OUTPUT
echo "PROMPT_EOF" >> $GITHUB_OUTPUT
- name: Run Claude Code to create adapted PR
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.generate-token.outputs.token }}
prompt: ${{ steps.create-prompt.outputs.prompt }}
claude_args: '--allowed-tools "Read,Edit,Write,Bash"'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No cleanup step. Failed runs leave garbage branches in cloudflare-docs repo. Add cleanup with if: always() condition.

env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No error handling: Add steps to handle failure:

  1. Cleanup step:
- name: Cleanup on failure
  if: failure()
  run: |
    cd cloudflare-docs
    git checkout main
    git branch -D sync-docs-pr-${{ github.event.pull_request.number }} 2>/dev/null || true
    git push origin --delete sync-docs-pr-${{ github.event.pull_request.number }} 2>/dev/null || true
  1. Notification comment:
- name: Comment on failure
  if: failure()
  uses: actions/github-script@v7
  with:
    script: |
      await github.rest.issues.createComment({
        owner: context.repo.owner,
        repo: context.repo.repo,
        issue_number: context.issue.number,
        body: '⚠️ Documentation sync failed. Check the [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})'
      });

Loading