Skip to content

feat: add PR preview deployments via Cloudflare Pages#300

Closed
Aureliolo wants to merge 4 commits intomainfrom
feat/pr-preview-deployments
Closed

feat: add PR preview deployments via Cloudflare Pages#300
Aureliolo wants to merge 4 commits intomainfrom
feat/pr-preview-deployments

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • New workflow: .github/workflows/pages-preview.yml — builds MkDocs + Astro site on PRs, injects a visible "Development Preview" banner, and deploys to Cloudflare Pages
  • Each PR gets a unique preview URL via branch-scoped Cloudflare Pages deployment
  • Preview URL is automatically commented on the PR
  • Security hardened: expression injection mitigated (env vars instead of inline expressions), fork PR guard on deploy job, SHA-pinned actions, persist-credentials: false
  • Bug fixes: fixed 3 broken links in docs/getting_started.md (MkDocs --strict failures), fixed docstring indentation in messenger.py (griffe parser warning)
  • Docs: added PR Preview section to CLAUDE.md CI documentation

Details

  • Build job always runs (catches build failures even on fork PRs)
  • Deploy job only runs for same-repo PRs (github.event.pull_request.head.repo.full_name == github.repository)
  • Requires CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID repository secrets
  • Uses cloudflare/wrangler-action@v3.14.1 (SHA-pinned)
  • Banner: sticky amber gradient bar at top of every HTML page with PR number

Test plan

  • Verify workflow triggers on PR with docs/site/mkdocs changes
  • Verify MkDocs builds successfully with --strict flag
  • Verify Astro builds successfully
  • Verify preview banner appears on all HTML pages
  • Verify Cloudflare Pages deployment succeeds (requires secrets)
  • Verify preview URL comment appears on PR
  • Verify fork PRs skip deploy job gracefully

Pre-reviewed by 8 agents, 7 findings addressed.

🤖 Generated with Claude Code

- Add pages-preview.yml workflow that builds site on PRs and deploys
  to Cloudflare Pages with a "Development Preview" banner injected
  into all HTML pages. Each PR gets a unique preview URL posted as
  a comment.
- Fix MkDocs strict-mode failures: replace 3 broken relative links
  in getting_started.md with GitHub URLs, fix docstring indentation
  in messenger.py (griffe warning).
- Document PR Preview workflow in CLAUDE.md.
Pre-reviewed by 7 agents, 7 findings addressed:
- Fix expression injection via github.head_ref (use env var)
- Fix expression injection via deployment-url output (use process.env)
- Add fork PR guard to skip deploy when secrets unavailable
- Remove unused artifact-uploaded output
- Use lambda in re.sub to prevent backslash misfire
- Port inline comments from pages.yml for consistency
- Fix CLAUDE.md wording about deploy job behavior
Copilot AI review requested due to automatic review settings March 11, 2026 16:02
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 11, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout de0fac2e4500dabe0009e67214ff5f5447ce83dd 🟢 5.9
Details
CheckScoreReason
Maintained⚠️ 23 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
SAST🟢 8SAST tool detected but not run on all commits
actions/actions/download-artifact 70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 🟢 6.2
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Packaging⚠️ -1packaging workflow not detected
Maintained🟢 1030 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits
actions/actions/github-script ed597411d8f924073f98dfc5c65a23a2325f34cd 🟢 7.7
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 10no binaries found in the repo
Maintained🟢 1013 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 9detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
SAST🟢 10SAST tool is run on all commits
actions/actions/setup-node 49933ea5288caeca8642d1e84afbd3f7d6820020 🟢 6.1
Details
CheckScoreReason
Maintained🟢 1012 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 9binaries present in source code
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 1branch protection is not maximal on development and all release branches
SAST🟢 9SAST tool is not run on all commits -- score normalized to 9
actions/actions/setup-python a26af69be951a213d495a4c3e4e4022e16d87065 🟢 5.3
Details
CheckScoreReason
Maintained🟢 34 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 3
Code-Review🟢 10all changesets reviewed
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 9SAST tool is not run on all commits -- score normalized to 9
actions/actions/upload-artifact bbbca2ddaa5d8feaa63e36b76fdaad77386f024f 🟢 6.2
Details
CheckScoreReason
Maintained🟢 1028 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits
actions/astral-sh/setup-uv 6b9c6063abd6010835644d4c2e1bef4cf5cd0fca UnknownUnknown
actions/cloudflare/wrangler-action da0e0dfe58b7a431659754fdf3f186c529afbe65 🟢 5.5
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained⚠️ 00 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 2dependency not pinned by hash detected -- score normalized to 2
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 10security policy file detected
SAST🟢 5SAST tool is not run on all commits -- score normalized to 5

Scanned Files

  • .github/workflows/pages-preview.yml

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the development workflow by integrating automated preview deployments for every pull request. This change allows developers and reviewers to easily visualize and interact with the proposed changes in a live environment before merging, thereby improving the quality assurance process and accelerating feedback cycles.

Highlights

  • PR Preview Deployments: Introduced a new GitHub Actions workflow (.github/workflows/pages-preview.yml) to build and deploy MkDocs and Astro sites to Cloudflare Pages for each pull request, including a "Development Preview" banner.
  • Unique Preview URLs: Each pull request now receives a unique, branch-scoped preview URL from Cloudflare Pages, which is automatically commented on the PR.
  • Security Enhancements: Implemented security hardening measures, including mitigating expression injection, adding a fork PR guard for the deploy job, pinning action SHAs, and setting persist-credentials: false.
  • Bug Fixes: Resolved three broken links in docs/getting_started.md and corrected docstring indentation in messenger.py to fix a griffe parser warning.
  • Documentation Update: Added a new "PR Preview" section to CLAUDE.md to document the new CI/CD functionality.
Changelog
  • CLAUDE.md
    • Added a new entry detailing the PR Preview workflow, including its purpose, deployment mechanism via Cloudflare Pages, and secret requirements.
  • docs/getting_started.md
    • Updated three relative links to external documentation files to use absolute GitHub URLs, resolving broken link issues.
  • src/ai_company/communication/messenger.py
    • Adjusted the indentation of a line within a docstring to correct a formatting issue.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/pages-preview.yml
Activity
  • The pull request underwent a pre-review by 8 agents, and 7 findings identified during this process have been addressed.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 11, 2026

Preview Deployment

URL: https://db785235.preview-dp2.pages.dev

Built from commit 532bcbf

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new workflow for deploying PR previews to Cloudflare Pages, a valuable addition for reviewing changes. The security considerations for the new workflow are well-described. The documentation updates are helpful, but I've identified an opportunity for improvement in docs/getting_started.md where the use of absolute URLs pointing to the main branch could be replaced with a more version-aware linking strategy. The minor docstring fix is a good correction.

Comment on lines +153 to +155
- [CONTRIBUTING.md](https://github.com/Aureliolo/synthorg/blob/main/.github/CONTRIBUTING.md) — branch, commit, and PR workflow
- [CLAUDE.md](https://github.com/Aureliolo/synthorg/blob/main/CLAUDE.md) — code conventions and quick command reference
- [DESIGN_SPEC.md](https://github.com/Aureliolo/synthorg/blob/main/DESIGN_SPEC.md) — full high-level design specification
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

While using absolute URLs to GitHub fixes the broken link issue with mkdocs --strict, it introduces a new problem: these links are now hardcoded to the main branch. This means that when viewing documentation for a specific version (e.g., a release tag or a feature branch in a PR preview), these links will incorrectly point to the main branch's version of the files, not the version corresponding to the documentation being viewed.

A more robust solution would be to use relative links that are correctly resolved by MkDocs. If the files are intended to be part of the documentation, consider moving or linking them into the docs directory. Alternatively, you could explore MkDocs plugins like mkdocs-redirects or mkdocs-awesome-pages-plugin to handle linking to files outside the docs_dir correctly.

Comment on lines +153 to +155
- [CONTRIBUTING.md](https://github.com/Aureliolo/synthorg/blob/main/.github/CONTRIBUTING.md) — branch, commit, and PR workflow
- [CLAUDE.md](https://github.com/Aureliolo/synthorg/blob/main/CLAUDE.md) — code conventions and quick command reference
- [DESIGN_SPEC.md](https://github.com/Aureliolo/synthorg/blob/main/DESIGN_SPEC.md) — full high-level design specification
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Absolute links hardcoded to main branch

The links now resolve to github.com/.../blob/main/.... While this fixes the MkDocs --strict build failure (the files live outside the docs/ hierarchy), every PR preview will point visitors to the main branch version of CONTRIBUTING.md, CLAUDE.md, and DESIGN_SPEC.md rather than to the PR's own content. This is especially misleading in the context of this PR, where the preview is intended to show the state of a branch. Consider whether the intent is to always reflect the latest main content (in which case this is fine) or whether these should be included in the docs hierarchy or linked differently.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/getting_started.md
Line: 153-155

Comment:
**Absolute links hardcoded to `main` branch**

The links now resolve to `github.com/.../blob/main/...`. While this fixes the MkDocs `--strict` build failure (the files live outside the `docs/` hierarchy), every PR preview will point visitors to the `main` branch version of `CONTRIBUTING.md`, `CLAUDE.md`, and `DESIGN_SPEC.md` rather than to the PR's own content. This is especially misleading in the context of this PR, where the preview is intended to show the state of a branch. Consider whether the intent is to always reflect the latest `main` content (in which case this is fine) or whether these should be included in the docs hierarchy or linked differently.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a pull-request preview deployment pipeline for the docs + site build, enabling per-PR Cloudflare Pages previews and surfacing the preview URL back on the PR. Also includes small documentation fixes to keep MkDocs --strict and docstring parsing happy.

Changes:

  • Add .github/workflows/pages-preview.yml to build MkDocs + Astro on PRs, inject a preview banner, deploy to Cloudflare Pages, and comment the preview URL.
  • Fix broken “Next Steps” links in docs/getting_started.md that caused MkDocs strict build failures.
  • Fix docstring indentation in src/ai_company/communication/messenger.py and document PR preview behavior in CLAUDE.md.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
.github/workflows/pages-preview.yml New PR workflow to build, banner-inject, deploy to Cloudflare Pages, and comment the preview URL
docs/getting_started.md Updates “Next Steps” links to avoid MkDocs strict link failures
src/ai_company/communication/messenger.py Docstring indentation adjustment to address parser warnings
CLAUDE.md Adds CI documentation describing PR preview deployments and requirements

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- ".github/workflows/pages-preview.yml"

permissions: {}

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This workflow lacks a concurrency block. Other workflows in this repo define concurrency (e.g., .github/workflows/ci.yml and pages.yml) to prevent overlapping runs; without it, repeated pushes to the same PR can trigger multiple builds/deploys and race to update the PR comment, increasing cost and making the latest preview harder to identify. Add a concurrency group keyed by workflow + PR number (and typically cancel in-progress for PR events).

Suggested change
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

Copilot uses AI. Check for mistakes.
Comment on lines +153 to +157
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

issues.listComments is called without pagination/per_page, so it will only scan the first page of comments. On PRs with many comments, this can fail to find the existing “## Preview Deployment” comment and create duplicates. Use per_page: 100 and paginate (e.g., via github.paginate) before searching for the existing comment.

Suggested change
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100,
}
);

Copilot uses AI. Check for mistakes.
Comment on lines +145 to +150
const body = [
'## Preview Deployment',
'',
`**URL:** ${url}`,
'',
`Built from commit \`${context.sha.substring(0, 7)}\``,
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

For pull_request events, context.sha typically refers to the synthetic merge commit (refs/pull/.../merge), not the PR head commit. The comment may therefore report a SHA that doesn’t match what contributors expect. Prefer using the PR head SHA from the event payload (e.g., context.payload.pull_request.head.sha) when generating the “Built from commit …” line.

Suggested change
const body = [
'## Preview Deployment',
'',
`**URL:** ${url}`,
'',
`Built from commit \`${context.sha.substring(0, 7)}\``,
const prHeadSha = context.payload?.pull_request?.head?.sha;
const effectiveSha = prHeadSha || context.sha;
const body = [
'## Preview Deployment',
'',
`**URL:** ${url}`,
'',
`Built from commit \`${effectiveSha.substring(0, 7)}\``,

Copilot uses AI. Check for mistakes.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Mar 11, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
preview 532bcbf Mar 11 2026, 04:12 PM

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3c7d1e17-ba3d-408d-9e93-5855af7bc2ec

📥 Commits

Reviewing files that changed from the base of the PR and between 2eac571 and 532bcbf.

📒 Files selected for processing (4)
  • .github/workflows/pages-preview.yml
  • CLAUDE.md
  • docs/getting_started.md
  • src/ai_company/communication/messenger.py
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Agent
  • GitHub Check: Greptile Review
  • GitHub Check: Workers Builds: preview
🧰 Additional context used
📓 Path-based instructions (3)
.github/workflows/*.yml

📄 CodeRabbit inference engine (CLAUDE.md)

.github/workflows/*.yml: Matrix: Python 3.14
Secret scanning: gitleaks workflow on push/PR + weekly schedule

Files:

  • .github/workflows/pages-preview.yml
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: No from __future__ import annotations — Python 3.14 has PEP 649
Use except A, B: syntax without parentheses (PEP 758) — ruff enforces this on Python 3.14
Type hints required on all public functions; mypy strict mode
Google-style docstrings required on public classes and functions (enforced by ruff D rules)
Line length: 88 characters (ruff)
Functions must be less than 50 lines; files must be less than 800 lines

Files:

  • src/ai_company/communication/messenger.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: Create new objects, never mutate existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement. For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Config vs runtime state: use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); use @computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields — including optional and tuple variants — instead of manual whitespace validators.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Handle errors explicitly, never silently swallow
Validate at system boundaries (user input, external APIs, config files)
Every module with business logic MUST have: from ai_company.observability import get_logger then logger = get_logger(__name__). Never use import logging / logging.getLogger() / print() in application code.
Variable name for logger must always be logger (not _logger, not log)
Always use event name constants from domain-specific modules under ai_company.observability.events (e.g. PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: from ai_company.observability.events.<domain> import EVENT_CONSTANT
Always use structured logging kwargs: `logger.info(EVENT, key=va...

Files:

  • src/ai_company/communication/messenger.py
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/pages.yml : CI: `.github/workflows/pages.yml` — builds Astro landing + MkDocs docs, merges, deploys to GitHub Pages on push to main
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: After the PR exists, use `/aurelio-review-pr` to handle external reviewer feedback
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/pages.yml : CI: `.github/workflows/pages.yml` — builds Astro landing + MkDocs docs, merges, deploys to GitHub Pages on push to main

Applied to files:

  • .github/workflows/pages-preview.yml
  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/zizmor.yml : Workflow security: `.github/workflows/zizmor.yml` — zizmor static analysis of GitHub Actions workflows on push to main and PRs (triggers only when workflow files change), SARIF upload to Security tab on push events only (fork PRs lack `security-events: write`)

Applied to files:

  • .github/workflows/pages-preview.yml
  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/release.yml : Release: `.github/workflows/release.yml` — Release Please (Google) auto-creates a release PR on every push to main. Merging the release PR creates a git tag (`vX.Y.Z`) + GitHub Release with changelog. Tag push triggers the Docker workflow to build version-tagged images. Uses `RELEASE_PLEASE_TOKEN` secret (PAT/GitHub App token) so tag creation triggers downstream workflows (GITHUB_TOKEN cannot). Config in `.github/release-please-config.json` and `.github/.release-please-manifest.json`.

Applied to files:

  • .github/workflows/pages-preview.yml
  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/docker.yml : CI: `.github/workflows/docker.yml` — build → scan → push to GHCR + cosign sign. Scans: Trivy (CRITICAL = hard fail, HIGH = warn-only) + Grype. CVE triage via `.github/.trivyignore.yaml` and `.github/.grype.yaml`. Images only pushed after scans pass. Triggers on push to main and version tags (`v*`).

Applied to files:

  • .github/workflows/pages-preview.yml
  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Always read `DESIGN_SPEC.md` before implementing any feature or planning any issue

Applied to files:

  • docs/getting_started.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/*.yml : Matrix: Python 3.14

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/dependabot.yml : Dependabot: daily uv + github-actions + docker updates, grouped minor/patch, no auto-merge

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: CI jobs: lint (ruff) + type-check (mypy src/ tests/) + test (pytest + coverage) run in parallel → ci-pass gate

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to .github/workflows/*.yml : Secret scanning: gitleaks workflow on push/PR + weekly schedule

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-11T15:09:59.075Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T15:09:59.075Z
Learning: Applies to docker/** : Docker: backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web: `nginxinc/nginx-unprivileged`, SPA routing, API/WebSocket proxy. Config: all Docker files in `docker/` — Dockerfiles, compose, `.env.example`.

Applied to files:

  • CLAUDE.md
🔇 Additional comments (10)
src/ai_company/communication/messenger.py (1)

293-294: LGTM!

Correct fix for the griffe parser warning — the continuation line is now properly indented under the bullet point.

docs/getting_started.md (1)

153-155: LGTM!

Using absolute GitHub URLs correctly resolves the MkDocs --strict build failures. These files reside outside the docs/ directory, so relative paths cannot resolve during the MkDocs build.

CLAUDE.md (1)

176-176: LGTM!

Documentation accurately describes the new PR preview workflow, including the security considerations (fork PR deploy skip, required secrets). Consistent with existing CI documentation style.

.github/workflows/pages-preview.yml (7)

13-17: LGTM!

Good security posture: workflow-level permissions: {} with job-level scoping, and concurrency group keyed on PR number to cancel stale builds.


74-102: LGTM!

Well-implemented banner injection:

  • Uses environment variable to avoid expression injection
  • Regex correctly handles <body> tags with attributes
  • count=1 prevents double-injection in edge cases
  • Explicit UTF-8 encoding

114-114: LGTM!

The fork guard correctly prevents the deploy job from running on fork PRs where secrets are inaccessible. This is the standard pattern for protecting secrets in PR workflows.


138-182: LGTM!

Well-implemented PR comment handling:

  • Uses environment variable for DEPLOY_URL to mitigate expression injection
  • Gracefully handles missing deployment URL
  • Uses paginate to handle PRs with many comments
  • Updates existing comment instead of creating duplicates

116-119: The deployments: write permission is required and correctly configured. The cloudflare/wrangler-action uses this permission to create and update GitHub Deployment records, as documented in Cloudflare's official examples. This is not extraneous—removing it would break deployment tracking. The current permissions follow the correct pattern for this action.

			> Likely an incorrect or invalid review comment.

129-136: The SHA da0e0dfe58b7a431659754fdf3f186c529afbe65 correctly corresponds to v3.14.1, which is the latest stable release of cloudflare/wrangler-action (released March 15, 2025). No action needed.


26-28: The checkout action SHA de0fac2e4500dabe0009e67214ff5f5447ce83dd is the official release SHA for actions/checkout v6 (v6.0.2). The pinning is correct.


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added PR preview functionality enabling preview deployments of documentation and landing page changes for pull requests to Cloudflare Pages.
  • Documentation

    • Updated getting started guide links to use absolute GitHub URLs.
    • Added documentation for the PR preview workflow and deployment process, including required configuration details.

Walkthrough

This pull request introduces a new GitHub Actions workflow for generating PR preview sites, updates documentation describing the preview workflow and deployment process, fixes documentation links from relative to absolute GitHub URLs, and makes a minor formatting adjustment to a docstring.

Changes

Cohort / File(s) Summary
CI/CD Workflow
.github/workflows/pages-preview.yml
New GitHub Actions workflow that triggers on PRs to main, builds MkDocs documentation and Astro landing page in parallel, merges outputs while preventing overwrites, injects a preview banner, uploads the merged site as an artifact, and deploys to Cloudflare Pages with PR comment updates.
Documentation
CLAUDE.md, docs/getting_started.md
CLAUDE.md updated with PR Preview workflow description including Cloudflare Pages deployment details and required secrets; docs/getting_started.md updated with absolute GitHub URLs replacing relative links for CONTRIBUTING.md, CLAUDE.md, and DESIGN_SPEC.md.
Code Maintenance
src/ai_company/communication/messenger.py
Minor indentation correction in docstring bullet point under receive() method with no functional impact.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add PR preview deployments via Cloudflare Pages' clearly and specifically summarizes the main change—adding a new workflow for PR preview deployments to Cloudflare Pages, which is the primary focus of the changeset.
Description check ✅ Passed The PR description is detailed and directly related to the changeset, covering the new workflow, security hardening, bug fixes, and documentation updates that match the files modified in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/pr-preview-deployments
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/pr-preview-deployments

Comment @coderabbitai help to get the list of available commands and usage tips.

- Add concurrency group to cancel stale preview builds on rapid pushes
- Paginate listComments to avoid missing existing preview comment
- Use PR head SHA instead of merge commit SHA in preview comment
Copilot AI review requested due to automatic review settings March 11, 2026 16:12
Comment on lines +105 to +122
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: preview-site
path: _site
retention-days: 5

deploy-preview:
name: Deploy Preview
needs: build
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
deployments: write
steps:
- name: Download preview artifact
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Artifact upload/download version mismatch

upload-artifact is pinned at v7 while download-artifact is pinned at v8. These are different major versions. GitHub's artifact actions historically introduced breaking format changes across major versions (notably from v3→v4), and mixing major versions between the upload and download steps of the same workflow run risks a format incompatibility that would silently produce a corrupted or empty artifact download — failing the deployment without a clear error.

Both pins should be aligned to the same major version. The existing pages.yml workflow sidesteps this entirely by using actions/upload-pages-artifact (which pairs with the GitHub Pages deploy action), so there's no prior art in this repo to lean on. Align both to the same version, e.g.:

      - name: Upload preview artifact
        uses: actions/upload-artifact@<sha> # v8
        with:
          name: preview-site
          path: _site
          retention-days: 5

and

      - name: Download preview artifact
        uses: actions/download-artifact@<sha> # v8
        with:
          name: preview-site
          path: _site
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/pages-preview.yml
Line: 105-122

Comment:
**Artifact upload/download version mismatch**

`upload-artifact` is pinned at `v7` while `download-artifact` is pinned at `v8`. These are different major versions. GitHub's artifact actions historically introduced breaking format changes across major versions (notably from v3→v4), and mixing major versions between the upload and download steps of the same workflow run risks a format incompatibility that would silently produce a corrupted or empty artifact download — failing the deployment without a clear error.

Both pins should be aligned to the same major version. The existing `pages.yml` workflow sidesteps this entirely by using `actions/upload-pages-artifact` (which pairs with the GitHub Pages deploy action), so there's no prior art in this repo to lean on. Align both to the same version, e.g.:

```yaml
      - name: Upload preview artifact
        uses: actions/upload-artifact@<sha> # v8
        with:
          name: preview-site
          path: _site
          retention-days: 5
```
and
```yaml
      - name: Download preview artifact
        uses: actions/download-artifact@<sha> # v8
        with:
          name: preview-site
          path: _site
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

permissions:
contents: read
pull-requests: write
deployments: write
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

deploy-preview requests deployments: write, but this workflow doesn't appear to use the GitHub Deployments API (it only downloads an artifact, deploys to Cloudflare, and posts a PR comment). Consider removing deployments: write to keep the job least-privileged, or add a note/step showing why it's required.

Suggested change
deployments: write

Copilot uses AI. Check for mistakes.
@Aureliolo
Copy link
Copy Markdown
Owner Author

Closing — will recreate with all review feedback incorporated in a clean PR.

@Aureliolo Aureliolo closed this Mar 11, 2026
Aureliolo added a commit that referenced this pull request Mar 11, 2026
## Summary

- **New workflow**: `.github/workflows/pages-preview.yml` — builds
MkDocs + Astro on PRs, injects "Development Preview" banner, deploys to
Cloudflare Pages
- Each PR gets a unique preview URL at
`pr-<number>.synthorg-pr-preview.pages.dev`
- Preview URL auto-commented on the PR (paginated comment search,
updates existing comment on re-push)
- **Security hardened**: env vars for expression injection mitigation,
fork PR guard, SHA-pinned actions, `persist-credentials: false`,
least-privilege permissions
- **Bug fixes**: 3 broken links in `docs/getting_started.md` (MkDocs
`--strict`), docstring indentation in `messenger.py` (griffe warning)
- **Docs**: CLAUDE.md CI section updated with PR Preview details

## Review feedback incorporated

All valid findings from PR #300 reviewers (Gemini, Greptile, Copilot)
addressed:
- Concurrency group with cancel-in-progress (Greptile + Copilot)
- Paginated `listComments` to avoid missing existing comment (Copilot)
- PR head SHA instead of merge commit SHA in comment (Copilot)
- Removed unused `deployments: write` permission (Copilot)
- Wrangler run step instead of action (fixes env var expansion bug)
- PR number in URL instead of branch slug (cleaner, shorter)

Dismissed: absolute links to main in getting_started.md (intentional —
files outside docs/ hierarchy)

## Test plan

- [ ] Verify workflow triggers on PR with docs/site/mkdocs changes
- [ ] Verify MkDocs + Astro build succeeds
- [ ] Verify preview banner appears on all HTML pages
- [ ] Verify Cloudflare Pages deployment succeeds
- [ ] Verify preview URL comment appears on PR with correct SHA
- [ ] Verify concurrency cancels stale builds on rapid push
- [ ] Verify fork PRs skip deploy job gracefully

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants