Skip to content

Add Poseidon PR Review Command#129

Merged
ecairol merged 3 commits into
trunkfrom
add/poseidon-pr-review-command
Jun 1, 2026
Merged

Add Poseidon PR Review Command#129
ecairol merged 3 commits into
trunkfrom
add/poseidon-pr-review-command

Conversation

@ecairol

@ecairol ecairol commented May 31, 2026

Copy link
Copy Markdown
Contributor

What

Adds a new CLI command, poseidon:pr-review, that runs the Poseidon AI code review against a pull request from your local machine, using your own gh and claude authentication (no API keys required).

Why

To extend poseidon-actions/pr-review ability to GitHub organizations outside a8cteam51.
Specific use case: PR reviews on Automattic's GitHub org, eg: Automattic/wp-calypso, Automattic/sensei

How it works

  1. Parses a PR URL or OWNER/REPO#N and pre-flights access with gh pr view.
  2. Fetches the Poseidon review system prompt at runtime from a8cteam51/poseidon-actions, so it always uses the latest upstream version automatically
  3. Clones the target repo into a temp dir (printed to the console) and gh pr checkout --detach, so the agent can read AGENTS.md/.agents/ and surrounding
    code — mirroring the Action's actions/checkout.
  4. Runs the local claude CLI headless against the PR.
  5. Cleans up the temp dir + prompt file in a finally.
  6. Optionally, posts the review as a comment (under your gh username). Otherwise, the review is printed on the Terminal

Usage

# Print the review to the terminal (default — posts nothing)
team51 poseidon:pr-review https://github.com/Automattic/wpvdb/pull/18

# Post the review to the PR as your gh user (asks for confirmation)
team51 poseidon:pr-review Automattic/wpvdb#18 --post-to-github

# Skip the clone and read the PR via the GitHub API (faster, weaker grounding)
team51 poseidon:pr-review https://github.com/Automattic/wpvdb/pull/18 --no-clone

Flags: --post-to-github, --no-clone, --model (default claude-opus-4-8), --max-turns (default 45)
Screenshot 2026-05-30 at 7 36 25 PM

Summary by CodeRabbit

  • New Features
    • Added a poseidon:pr-review command to run AI-powered PR reviews from a PR URL or OWNER/REPO#N.
    • Validates local tooling, resolves authenticated GitHub identity, and fails early with diagnostics if access is blocked.
    • Fetches the review system prompt at runtime, supports optional local clone or no-clone workflows, and streams AI output to the console.
    • Optionally posts reviews to GitHub (with confirmation) and cleans up temporary artifacts after completion.

Allows users to run AI code reviews on pull requests using local `gh` and `claude` CLIs.

Enhances accessibility across different repositories, including those outside the a8cteam51 organization.

Synced with Poseidon yaml file.
@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a06acba7-d3e8-406a-8b8e-b7daa136aa1c

📥 Commits

Reviewing files that changed from the base of the PR and between e08fc97 and 997f547.

📒 Files selected for processing (1)
  • commands/Poseidon_PR_Review.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • commands/Poseidon_PR_Review.php

Walkthrough

Adds a new Symfony Console command poseidon:pr-review that parses a PR reference, validates claude and gh access, fetches the Poseidon system prompt from a8cteam51/poseidon-actions via the GitHub API, extracts and validates the --append-system-prompt payload, composes a final prompt with PR target/context and conditional blocks (--no-clone, terminal-only), writes a temp prompt file, optionally clones/checks out the PR, runs claude streaming output, optionally posts the review to GitHub after confirmation, and always cleans up temporary artifacts.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: addition of a new Poseidon PR Review command. It is concise, clear, and directly reflects the primary purpose of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
commands/Poseidon_PR_Review.php (2)

129-142: ⚡ Quick win

Replace exit() calls with exceptions for proper Symfony Console lifecycle.

Using exit() in initialize() bypasses Symfony Console's error handling and makes the command untestable. Throw RuntimeException instead—Symfony Console will catch it, display the error, and return the appropriate exit code.

Proposed fix
 		if ( ! $this->command_exists( 'claude' ) ) {
-			$output->writeln( '<error>The `claude` CLI is not installed or not on PATH. Install Claude Code and try again.</error>' );
-			exit( Command::FAILURE );
+			throw new \RuntimeException( 'The `claude` CLI is not installed or not on PATH. Install Claude Code and try again.' );
 		}

 		$this->gh_username = $this->resolve_gh_username( $output );
 		if ( null === $this->gh_username ) {
-			exit( Command::FAILURE );
+			throw new \RuntimeException( 'Could not resolve GitHub username. See error above.' );
 		}

 		$this->pr_title = $this->resolve_pr_title( $output );
 		if ( null === $this->pr_title ) {
-			exit( Command::FAILURE );
+			throw new \RuntimeException( 'Could not access the pull request. See error above.' );
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@commands/Poseidon_PR_Review.php` around lines 129 - 142, The initialize()
flow currently calls exit() in three places — when command_exists('claude') is
false and after resolve_gh_username() or resolve_pr_title() return null — which
bypasses Symfony Console; replace each exit(Command::FAILURE) with throwing a
RuntimeException (e.g. throw new \RuntimeException('The `claude` CLI is not
installed or not on PATH. Install Claude Code and try again.');) and for the
other two cases throw meaningful RuntimeException messages where
resolve_gh_username() or resolve_pr_title() return null; keep the same output
text presently sent to $output->writeln and ensure you import or fully qualify
RuntimeException so Symfony handles the error lifecycle and exit code.

384-393: 💤 Low value

Quote parsing doesn't handle escaped quotes in the YAML string.

strpos($yaml, '"', $start) finds the first unescaped double-quote, but if the upstream prompt contains \" (escaped quotes), this will truncate the extracted prompt prematurely. The sanity check at line 395 helps catch this, but a malformed prompt extraction would produce a confusing error.

Consider using a proper YAML parser like symfony/yaml for robustness, or at minimum handle \" sequences.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@commands/Poseidon_PR_Review.php` around lines 384 - 393, The current
extraction of the system prompt using strpos($yaml, '"', $start) is vulnerable
to escaped quotes and should be replaced: either parse the action.yml with a
proper YAML parser (e.g., symfony/yaml's Yaml::parseFile and then pull the
system prompt key) or, if you must keep string-scanning, replace the strpos call
with a loop that advances from $start and finds the next unescaped double-quote
(skip any \" by checking preceding backslashes) before computing $end; update
the subsequent $prompt/substr and preg_replace logic to use that safe $end and
still trim indentation from $prompt derived from $matches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@commands/Poseidon_PR_Review.php`:
- Around line 1-2: This file is missing the strict types declaration; add
declare(strict_types=1); immediately after the opening <?php tag (before any
code, class or function definitions) so the typed properties and return type
declarations in this file are enforced at runtime.
- Around line 217-241: The Process instantiation that builds $claude is passing
'--allowedTools' followed by multiple separate args
('Bash','Read','Write','Edit','Glob','Grep','WebFetch','WebSearch'); change this
so '--allowedTools' is followed by a single string argument with comma-separated
tool rules (e.g. "--allowedTools", "Read,Edit,Bash,WebFetch") or remove the
'--allowedTools' entry entirely if it's redundant with '--permission-mode'
bypassPermissions; update the args array in the Process constructor where
$claude is created to use the single-string form (reference the '--allowedTools'
token and the $claude Process creation to locate the code).

---

Nitpick comments:
In `@commands/Poseidon_PR_Review.php`:
- Around line 129-142: The initialize() flow currently calls exit() in three
places — when command_exists('claude') is false and after resolve_gh_username()
or resolve_pr_title() return null — which bypasses Symfony Console; replace each
exit(Command::FAILURE) with throwing a RuntimeException (e.g. throw new
\RuntimeException('The `claude` CLI is not installed or not on PATH. Install
Claude Code and try again.');) and for the other two cases throw meaningful
RuntimeException messages where resolve_gh_username() or resolve_pr_title()
return null; keep the same output text presently sent to $output->writeln and
ensure you import or fully qualify RuntimeException so Symfony handles the error
lifecycle and exit code.
- Around line 384-393: The current extraction of the system prompt using
strpos($yaml, '"', $start) is vulnerable to escaped quotes and should be
replaced: either parse the action.yml with a proper YAML parser (e.g.,
symfony/yaml's Yaml::parseFile and then pull the system prompt key) or, if you
must keep string-scanning, replace the strpos call with a loop that advances
from $start and finds the next unescaped double-quote (skip any \" by checking
preceding backslashes) before computing $end; update the subsequent
$prompt/substr and preg_replace logic to use that safe $end and still trim
indentation from $prompt derived from $matches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b33da8ee-66db-4b87-995b-c78e03ddcc1b

📥 Commits

Reviewing files that changed from the base of the PR and between 2dd426c and 30b85b5.

📒 Files selected for processing (1)
  • commands/Poseidon_PR_Review.php

Comment on lines +1 to +2
<?php

@coderabbitai coderabbitai Bot May 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add declare(strict_types=1); declaration.

As per coding guidelines, PHP files should use declare(strict_types=1); where appropriate. This new file uses typed properties and return type declarations throughout, making strict types appropriate.

Proposed fix
 <?php
+declare(strict_types=1);

 namespace WPCOMSpecialProjects\CLI\Command;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<?php
<?php
declare(strict_types=1);
namespace WPCOMSpecialProjects\CLI\Command;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@commands/Poseidon_PR_Review.php` around lines 1 - 2, This file is missing the
strict types declaration; add declare(strict_types=1); immediately after the
opening <?php tag (before any code, class or function definitions) so the typed
properties and return type declarations in this file are enforced at runtime.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Other commands don't have it, for consistency, I prefer not to add it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@ecairol, understood — keeping consistency with the existing command files makes sense. I'll note this for future reviews.


✏️ Learnings added
Learnt from: ecairol
Repo: a8cteam51/team51-cli PR: 129
File: commands/Poseidon_PR_Review.php:1-2
Timestamp: 2026-05-31T02:11:12.697Z
Learning: In the `a8cteam51/team51-cli` repository, PHP command files under the `commands/` directory do not use `declare(strict_types=1);`. Do not suggest adding strict types declarations to files in this directory, as the project convention is to omit it for consistency across all commands.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment thread commands/Poseidon_PR_Review.php
@ecairol ecairol requested review from Ninodevo and ahegyes May 31, 2026 15:10
@ahegyes

ahegyes commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

👋 I learned last week that there is an ongoing Systems project to move repos from the github.com/Automattic to the Automattic org in GitHub Enterprise; that is the reason why all our public email were added to GHE a couple of weeks ago;

Does this still need to exist if we will be getting the Claude Opus 4.8 review on each PR once we get the repos in GHE? Maybe a cleaner solution would be to simply install this skill locally for work on WPCOM in the mean time? https://github.a8c.com/Automattic/claude-code-plugins/tree/trunk/plugins/systems-review

@Ninodevo

Ninodevo commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

@ahegyes which repos will be moved? All of them? Even our sites/plugins? I think we can add this because I just figured out that Poseidon Reviews don't work on our public repos, for example, Team51 CLI, and this is a good way to be able to review it. I think the systems skill is mostly for work on WPCOM, or is it a general review?

@ecairol before merging this I would fix the commands so if you just use team51 poseidon:pr-review it would prompt you for the PR, currently it just fails

@ahegyes

ahegyes commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

@ahegyes which repos will be moved? All of them? Even our sites/plugins?

I'm not entirely sure but I think the current scope are all private repos on http://github.com/Automattic

@ecairol

ecairol commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

before merging this I would fix the commands so if you just use team51 poseidon:pr-review it would prompt you for the PR,

@Ninodevo good call, thanks for flagging. Implemented in 997f547.

@ecairol ecairol merged commit a5b6002 into trunk Jun 1, 2026
4 of 5 checks passed
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.

3 participants