Open Integration PR
Read pr_order_file JSON produced by analyze-prs, generate a rich PR description
(per-PR details, complexity tags, merge outcomes, optional audit verdict), generate 1–3
arch-lens diagrams, carry forward Closes #N/Fixes #N references from original PR
bodies so linked issues auto-close on merge, create the integration PR via
gh pr create --body-file, close each collapsed PR with a comment referencing the new
PR, and output pr_url=<url>.
Arguments
/autoskillit:open-integration-pr {integration_branch} {base_branch} {pr_order_file} [audit_verdict] [conflict_report_paths]
integration_branch— integration branch name (e.g.pr-batch/pr-merge-20250228-143052)base_branch— PR target branch (e.g.main)pr_order_file— absolute path to JSON produced byanalyze-prsaudit_verdict(optional) —GO,NO GO, or empty string when audit was skippedconflict_report_paths(optional) — comma-separated list of absolute paths to conflict resolution report files, produced byresolve-merge-conflicts. When provided and non-empty, embed a "Conflict Resolution Decisions" section in the PR body.
When to Use
- Called by
merge-prsafter all PRs have been merged into the integration branch - Invoked via
run_skillas the final step before CI watch
Critical Constraints
NEVER:
- Create files outside
temp/open-integration-pr/(except the temp body file forgh pr create --body-file) - Modify any source code
- Fail the pipeline if
ghis unavailable or not authenticated — outputpr_url=(empty) and exit successfully - Close original PRs before the integration PR is successfully created
ALWAYS:
- Check
gh auth statusbefore attempting any GitHub operations - Output
pr_url=<url>on the last output line (empty string when GitHub unavailable) - Carry forward ALL
Closes #NandFixes #Nlines found in original PR bodies - Use
gh pr create --body-file(never inline body via--body)
Workflow
Step 1: Parse Arguments
Parse four positional args: integration_branch, base_branch, pr_order_file,
audit_verdict (last one may be absent or empty string). Parse the optional fifth
positional argument conflict_report_paths (may be absent or empty string). Split on ,
to get a list of paths; filter out any empty strings. Store as conflict_report_path_list.
Step 2: Read pr_order_file
Read the JSON file. Extract: prs array (each: number, title, branch,
complexity, additions, deletions, overlap_with_pr_numbers, files_changed). Also read
base_branch from JSON as confirmation. Store the PR list as pr_list.
Step 3: Fetch Closes/Fixes References from Original PR Bodies
For each PR in pr_list:
gh pr view {number} --json body -q .body 2>/dev/null
Extract every line matching (Closes|Fixes|Resolves)\s+#\d+ (case-insensitive).
Deduplicate across all PRs. Store as closing_refs (list of strings like Closes #42).
Skip gracefully if gh is unavailable — closing_refs remains empty.
Step 4: Get Changed Files
git diff --name-only {base_branch}..{integration_branch}
git diff --diff-filter=A --name-only {base_branch}..{integration_branch}
git diff --diff-filter=M --name-only {base_branch}..{integration_branch}
Store as changed_files, new_files, modified_files.
Step 4b: Load Conflict Resolution Reports
- If
conflict_report_path_listis empty: skip — setconflict_resolution_table = "". - For each path in
conflict_report_path_list:- Read the file.
- Extract the
## Per-File Resolution Decisionstable (all lines from the| File |header through the last table row).
- Concatenate all extracted tables (one per report, separated by a blank line if multiple).
- Store as
conflict_resolution_table.
This step is skipped gracefully if any path is missing — log a warning and exclude that file.
Step 4c: Partition Files by Domain
python3 -c "
from autoskillit.execution.pr_analysis import partition_files_by_domain
import json, sys
files = json.loads(sys.argv[1])
result = partition_files_by_domain(files)
print(json.dumps(result))
" '["path/to/file.py", ...]'
Pass changed_files as a JSON array argument. Store the parsed dict as domain_partitions.
Skip entirely and set domain_partitions = {} if changed_files is empty.
Step 4d: Fetch Domain Diffs (parallel)
For each domain name D in domain_partitions where domain_partitions[D] is non-empty,
run the following in parallel (issue all Bash calls in a single message):
git diff {base_branch}..{integration_branch} -- {space-separated list of files in domain D}
Store results as domain_diffs: dict[str, str] mapping domain name → diff text.
If a domain's diff text exceeds 12 000 characters, truncate to the first 12 000 characters
and append \n... [truncated — diff exceeds 12 000 chars]. Domains with empty diffs are
removed from domain_diffs.
Step 4e: Identify PRs per Domain
For each domain D in domain_partitions, find every PR in pr_list whose
files_changed list intersects with domain_partitions[D].
domain_pr_numbers = {
domain: [
pr["number"]
for pr in pr_list
if set(pr.get("files_changed", [])) & set(domain_partitions[domain])
]
for domain in domain_partitions
}
Store as domain_pr_numbers: dict[str, list[int]].
Step 4f: Fetch Domain Commits (parallel)
For each domain D in domain_diffs (domains that actually have diff content), run in
parallel (all Bash calls in a single message):
git log {base_branch}..{integration_branch} --oneline -- {space-separated files in domain D}
Store as domain_commits: dict[str, list[str]] (each entry is a list of "sha message" strings).
Empty results are stored as empty lists.
Step 4g: Run Parallel Domain Analysis Subagents
For each domain D in domain_diffs, spawn a Task subagent (model: sonnet) in a single
parallel message. Issue all Task calls in a single message to maximize parallelism.
Skip domains with no diff content (not in domain_diffs) — do not spawn subagents for them.
Each subagent receives a prompt with:
- The domain name
- The list of files changed in the domain
- The diff content (already truncated at 12 000 chars)
- The PR numbers and titles for PRs touching this domain (look up titles from
pr_list) - The commit one-liners for the domain
The subagent is instructed to return ONLY a JSON object with this exact shape:
{
"domain": "Server/MCP Tools",
"summary": "3-4 sentence description of what changed and why it matters",
"key_changes": ["concise description of change 1", "concise description of change 2"],
"pr_numbers": [42, 47],
"commit_count": 5
}
Parse each subagent's output as JSON. If parsing fails for a domain, log a warning and
omit that domain from domain_summaries. Store the collected results as
domain_summaries: list[dict].
The 7 canonical domain names are: Server/MCP Tools, Pipeline/Execution, Recipe/Validation, CLI/Workspace, Skills, Tests, Core/Config/Infra.
Step 5: Select Arch-Lens Lenses
Spawn a subagent (Task tool, model: sonnet) with changed_files and the same lens
menu as open-pr. Instruct it to return 1–3 lens names using the same development
lens guard.
Step 6: Generate Arch-Lens Diagrams
For each selected lens, follow this exact sequence:
CRITICAL: Do NOT output any prose status text between lens iterations. After completing all sub-steps for one lens (including mermaid extraction and validation), immediately begin sub-step 1 (Write the PR context file) for the next lens. Progress announcements like "Diagram generated. Now calling X:" create end_turn windows that cause stochastic session termination.
1. Write the PR context to a file using the Write tool:
- Path:
temp/open-integration-pr/pr_arch_lens_context_{YYYY-MM-DD_HHMMSS}.md - Content: The following PR context block, with placeholders filled in:
# PR Context — Changed Files
This diagram is for a Pull Request. Focus the diagram on the areas of the codebase affected by these changes. Do not create a generic whole-project diagram.
## New files (use ★ prefix on these nodes):
{list of new_files from Step 4, or "None"}
## Modified files (use ● prefix on these nodes):
{list of modified_files from Step 4, or "None"}
## Instructions:
- Focus exploration and the diagram on the architectural areas these files belong to
- Use `★` prefix on nodes representing new files/components
- Use `●` prefix on nodes representing modified files/components
- Leave unchanged components unmarked (include them only if needed for context/connectivity)
- The diagram should help PR reviewers understand the architectural impact of these specific changes
2. Immediately call the Skill tool to load the arch-lens skill (e.g., /autoskillit:arch-lens-module-dependency).
The loaded skill will read the PR context file written in step 1 above.
3. Follow the loaded skill's instructions to explore the codebase and generate the diagram.
The arch-lens skills write their output to temp/arch-lens-{lens-name}/ (relative to the current working directory). After each skill
runs, read the generated markdown file and extract the mermaid code block(s).
After extracting the mermaid block, inspect its content for ★ or ● characters:
- If the block contains at least one
★or●→ add it tovalidated_diagrams. - If the block contains neither → discard this diagram; do not add it to the list.
Step 7: Compose PR Body
Write to temp/open-integration-pr/pr_body_{timestamp}.md. (relative to the current working directory)
## Integration Summary
Collapsed {N} PRs into `{integration_branch}` targeting `{base_branch}`.
## Merged PRs
| # | Title | Complexity | Additions | Deletions | Overlaps |
|---|-------|-----------|-----------|-----------|---------|
| #{number} | {title} | {complexity} | +{additions} | -{deletions} | {overlap_with_pr_numbers or "—"} |
...
{If domain_summaries is non-empty:}
## Domain Analysis
{For each entry in domain_summaries (ordered by domain name):}
### {entry.domain}
{entry.summary}
**Key changes:**
{For each item in entry.key_changes:}
- {item}
**Contributing PRs:** {comma-separated #{N} for each N in entry.pr_numbers, or "—" if empty}
**Commits:** {entry.commit_count} commit(s)
{If audit_verdict is non-empty:}
## Audit
**Verdict:** {audit_verdict}
{If conflict_resolution_table is non-empty:}
## Conflict Resolution Decisions
The following files had merge conflicts that were automatically resolved during pipeline integration.
{conflict_resolution_table}
{If validated_diagrams non-empty:}
## Architecture Impact
{For each validated diagram:}
### {Lens Name} Diagram
```mermaid
{diagram content}
{For each item in closing_refs:} {Closes #N}
🤖 Generated with Claude Code via AutoSkillit
### Step 8: Check GitHub Availability
```bash
gh auth status 2>/dev/null
If exit code non-zero: output pr_url= and exit successfully.
Step 9: Create Integration PR
gh pr create \
--base {base_branch} \
--head {integration_branch} \
--title "Integration: collapsed PRs #{numbers} into {base_branch}" \
--body-file temp/open-integration-pr/pr_body_{timestamp}.md
{numbers} = comma-separated PR numbers (e.g., #42, #47, #51).
Capture the new PR URL as new_pr_url. Extract the PR number from the URL as
new_pr_number.
Step 10: Close Original PRs
For each PR in pr_list:
gh pr close {number} --comment "Collapsed into integration PR #{new_pr_number} ({new_pr_url})"
Continue even if individual close operations fail (log warning, do not exit).
Output
pr_url = {new_pr_url}