Skip to content
Open
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
60 changes: 60 additions & 0 deletions .github/workflows/bug-fixer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Bug Fixer Agent

on:
issues:
types: [labeled]
workflow_dispatch:
inputs:
issue_url:
description: 'GitHub issue URL'
required: true
type: string

permissions:
id-token: write
contents: write
pull-requests: write
issues: write

jobs:
fix-bug:
if: github.event.label.name == 'bug' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Determine issue URL
id: issue
env:
INPUT_URL: ${{ inputs.issue_url }}
EVENT_URL: ${{ github.event.issue.html_url }}
EVENT_NAME: ${{ github.event_name }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
echo "url=$INPUT_URL" >> "$GITHUB_OUTPUT"
else
echo "url=$EVENT_URL" >> "$GITHUB_OUTPUT"
fi

- name: Checkout
uses: actions/checkout@v6

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.HARNESS_AWS_ROLE_ARN }}
aws-region: us-west-2

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'

- name: Setup uv
uses: astral-sh/setup-uv@v7

- name: Run Bug Fixer Agent
working-directory: agents
env:
HARNESS_ARN: ${{ secrets.HARNESS_ARN }}
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
ISSUE_URL: ${{ steps.issue.outputs.url }}
run: uv sync && uv run python -m bug_fixer.main --issue "$ISSUE_URL"
81 changes: 81 additions & 0 deletions .github/workflows/feature-builder.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Feature Builder Agent

on:
workflow_dispatch:
inputs:
devex_doc:
description: 'Path to devex doc (relative to repo root)'
required: true
type: string
impl_doc:
description: 'Path to implementation plan (relative to repo root)'
required: true
type: string
feature_name:
description: 'Feature name (used for branch naming)'
required: true
type: string

permissions:
id-token: write
contents: write
pull-requests: write

jobs:
build-feature:
runs-on: ubuntu-latest
steps:
- name: Validate inputs
env:
FEATURE_NAME: ${{ inputs.feature_name }}
DEVEX_DOC: ${{ inputs.devex_doc }}
IMPL_DOC: ${{ inputs.impl_doc }}
run: |
if [[ ! "$FEATURE_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
echo "Error: feature_name must be alphanumeric with hyphens/underscores only"
exit 1
fi
if [[ "$DEVEX_DOC" == *".."* ]] || [[ "$IMPL_DOC" == *".."* ]]; then
echo "Error: doc paths must not contain '..'"
exit 1
fi
if [[ ! "$DEVEX_DOC" == *.md ]]; then
echo "Error: devex_doc must be a .md file"
exit 1
fi
if [[ ! "$IMPL_DOC" == *.md ]]; then
echo "Error: impl_doc must be a .md file"
exit 1
fi

- name: Checkout
uses: actions/checkout@v6

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.HARNESS_AWS_ROLE_ARN }}
aws-region: us-west-2

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'

- name: Setup uv
uses: astral-sh/setup-uv@v7

- name: Run Feature Builder Agent
working-directory: agents
env:
HARNESS_ARN: ${{ secrets.HARNESS_ARN }}
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
DEVEX_DOC: ${{ inputs.devex_doc }}
IMPL_DOC: ${{ inputs.impl_doc }}
FEATURE_NAME: ${{ inputs.feature_name }}
run: |
uv sync
uv run python -m feature_builder.main \
--devex "../$DEVEX_DOC" \
--impl "../$IMPL_DOC" \
--name "$FEATURE_NAME"
3 changes: 3 additions & 0 deletions agents/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
config.yaml
__pycache__/
.venv/
40 changes: 40 additions & 0 deletions agents/bug_fixer/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Bug Fixer Agent — resolves GitHub issues labeled 'bug'.

Usage:
uv run bug_fixer/main.py --issue https://github.com/aws/agentcore-cli/issues/123
uv run bug_fixer/main.py --issue https://github.com/aws/agentcore-cli/issues/123 --config config.yaml
"""

import argparse
import sys
from pathlib import Path

from orchestrations.fix_and_review.orchestrator import run_pipeline

PROMPTS_DIR = Path(__file__).resolve().parent / "prompts"


def main():
parser = argparse.ArgumentParser(description="Bug Fixer Agent")
parser.add_argument("--issue", required=True, help="GitHub issue URL")
parser.add_argument("--config", default="config.yaml", help="Config YAML path")
parser.add_argument("--aws-profile", help="Override AWS profile")
parser.add_argument("--harness-arn", help="Override harness ARN")
args = parser.parse_args()

overrides = {}
if args.aws_profile:
overrides["aws_profile"] = args.aws_profile
if args.harness_arn:
overrides["harness_arn"] = args.harness_arn

return run_pipeline(
issue_url=args.issue,
config_path=args.config,
prompts_dir=PROMPTS_DIR,
**overrides,
)


if __name__ == "__main__":
sys.exit(main())
21 changes: 21 additions & 0 deletions agents/bug_fixer/prompts/executor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
You are a senior software engineer implementing a planned change across one or two TypeScript repos.

The plan:
{plan}

Instructions:
1. Follow the plan exactly. Make the code changes described.
2. COMMIT IMMEDIATELY after writing your changes: `git add -A && git commit -m "feat: {commit_message}"`
3. Run `npm run typecheck 2>&1 | tail -20`. If there are type errors, fix them and commit again.
4. Run ONLY targeted tests for files you changed:
- `npx vitest run --project unit path/to/relevant.test.ts 2>&1 | tail -30`
- Run 1-5 targeted test files, NOT the full suite.
5. If targeted tests fail, fix and commit again.
6. Push to remote: `git push origin {branch_name}`

CRITICAL RULES:
- COMMIT EARLY AND OFTEN. Your first commit should happen BEFORE running typecheck. Commit after every fix. A commit with typecheck errors is better than no commit at all.
- If typecheck has more than 5 errors, fix the most critical ones, commit what you have, and move on. Do NOT spend more than 3 attempts fixing typecheck.
- Do NOT run `npm run test:unit` (full suite). Only run targeted tests.
- CI will run the full test suite after the PR is created.
- Always pipe output through `| tail -30`.
21 changes: 21 additions & 0 deletions agents/bug_fixer/prompts/fixer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
You are a senior software engineer fixing issues found during code review.

The following findings were reported by reviewers. Address each one:

{findings_text}

Instructions:
1. Fix each finding, starting with Critical severity first, then High, Medium, Low.
2. If a finding is not applicable or is a false positive, explain why in a commit message.
3. Run `npm run typecheck 2>&1 | tail -20` in each affected repo after fixes.
4. Run ONLY targeted tests for files you changed:
- `npx vitest run --project unit path/to/relevant.test.ts 2>&1 | tail -30`
- Run 1-5 targeted test files, NOT the full suite.
5. If targeted tests fail, fix and re-run only those tests.
6. Commit: `git add -A && git commit -m "fix: address review findings round {round_number}"`
7. Push: `git push origin {branch_name}`

IMPORTANT:
- Do NOT run `npm run test:unit` (full suite). It takes too long. Only run targeted tests.
- CI will validate the full suite after PR creation.
- Always pipe test output through `| tail -30`.
20 changes: 20 additions & 0 deletions agents/bug_fixer/prompts/planner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
You are a senior software architect planning a fix for a GitHub issue.

You have access to two TypeScript repositories:
- agentcore-cli: AWS AgentCore CLI tool (Commander.js + Ink TUI, ~550 source files)
- agentcore-l3-cdk-constructs: AWS CDK L3 constructs for AgentCore (~17 test files, shares schemas with CLI)

The issue details are:
{issue_details}

Analyze the issue, explore the relevant code in both repos, and produce a structured implementation plan.

Your plan MUST include:
1. **Affected repos**: Which repos need changes (cli, cdk, or both)
2. **Files to change**: Exact file paths to modify, create, or delete
3. **Approach**: Step-by-step description of the changes
4. **Risks**: What could go wrong, edge cases to watch for
5. **Testing strategy**: What tests to add or modify, how to verify the fix
6. **Scope estimate**: small (1-3 files), medium (4-7 files), or large (8+ files)

Output the plan as structured markdown.
39 changes: 39 additions & 0 deletions agents/bug_fixer/prompts/reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
You are a senior code reviewer. Review ONLY the diff on the feature branch.

Issue being solved: {issue_summary}
Branch: {branch_name}
Repos: {cli_repo}, {cdk_repo}

Your assigned focus: {focus}
Files to focus on: {assigned_files}

Instructions:
1. Clone the repo: git clone --depth 10 --branch {branch_name} https://github.com/{cli_repo}.git agentcore-cli 2>&1 | tail -3
(If branch doesn't exist, clone main instead)
2. Run: cd agentcore-cli && git diff main
3. Read ONLY the changed files and their immediate context (the functions/classes that were modified).
4. If you need to check a caller or type, read at most 1-2 additional files. No more.
5. Produce your verdict.

{previous_findings_context}

CONSTRAINTS:
- Stay focused on the diff and immediately related code. Do not explore unrelated parts of the codebase.
- Focus on: correctness, breaking changes, obvious bugs, missing error handling. Skip style nits.
- If the code looks correct and doesn't break anything, approve it.
- Do NOT run npm install, npm test, or any build commands.

Output your review as a JSON object wrapped in ```json fences:
{{
"approved": boolean,
"findings": [
{{
"severity": "critical" | "high" | "medium" | "low",
"file": "path/to/file",
"line": number,
"description": "what's wrong",
"suggestion": "how to fix"
}}
]
}}
Output ONLY the JSON object in code fences. No other text before or after.
23 changes: 23 additions & 0 deletions agents/bug_fixer/prompts/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
You are setting up a development environment to solve a GitHub issue.

Steps:
1. Install tools and configure node 20 as default:
dnf install -y -q git nodejs20 > /dev/null 2>&1
ln -sf /usr/bin/node-20 /usr/local/bin/node
ln -sf /usr/lib/nodejs20/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm
export PATH=/usr/local/bin:$PATH
2. Authenticate GitHub: echo $GH_TOKEN | gh auth login --with-token
3. Configure git to use gh for auth: gh auth setup-git
4. Clone both repos:
- git clone https://github.com/{cli_repo}.git {cli_repo_name}
- git clone https://github.com/{cdk_repo}.git {cdk_repo_name}
5. Install dependencies: cd {cli_repo_name} && npm install 2>&1 | tail -3 && cd ..
6. Fetch the issue details: gh issue view {issue_url} --json title,body,labels,comments,assignees
7. Create a feature branch in both repos:
- cd {cli_repo_name} && git checkout -b {branch_name} && cd ..
- cd {cdk_repo_name} && git checkout -b {branch_name} && cd ..
8. Report back: the issue title, body, and which repos likely need changes based on the issue content.

IMPORTANT: Run each step as a separate shell command. Do not combine them. If tools are already installed, skip step 1.

Output the issue details as structured markdown with sections: Title, Body, Labels, and Initial Assessment.
10 changes: 10 additions & 0 deletions agents/config.yaml
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Workflow sets HARNESS_ARN secret but code never reads it; hardcoded personal ARN will be used in CI instead

Both .github/workflows/bug-fixer.yml and .github/workflows/feature-builder.yml export HARNESS_ARN: ${{ secrets.HARNESS_ARN }} as an env var, but nothing in agents/ reads environment variables — PipelineConfig only loads from config.yaml, and the workflows don't pass --harness-arn.

The hardcoded value in agents/config.yaml is arn:aws:bedrock-agentcore:us-west-2:603141041947:harness/IssueSolver_aidandal-8SL97TEXjS — a personal developer harness (and a personal AWS account ID checked into the repo). When these workflows run in CI they will always hit that personal harness and ignore the secret.

Fix options:

  1. Have PipelineConfig.from_yaml (or PipelineConfig itself) read HARNESS_ARN/AWS_PROFILE/etc. from env vars, with env taking precedence over YAML.
  2. Pass --harness-arn "$HARNESS_ARN" on the uv run python -m ... line in each workflow.
  3. Remove the account-specific ARN from the committed config.yaml (leave it as a placeholder/empty) and require env/flag override in non-local runs.

Option 1 is probably cleanest since it also solves the aws_profile issue below.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
harness_arn: "arn:aws:bedrock-agentcore:us-west-2:603141041947:harness/IssueSolver_aidandal-8SL97TEXjS"
region: "us-west-2"
aws_profile: "deploy"
model_id: "global.anthropic.claude-opus-4-7"
min_reviewers: 3
max_reviewers: 5
max_review_rounds: 5
repos:
cli: "aws/agentcore-cli"
cdk: "aws/agentcore-l3-cdk-constructs"
10 changes: 10 additions & 0 deletions agents/config.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
harness_arn: "arn:aws:bedrock-agentcore:us-west-2:YOUR_ACCOUNT_ID:harness/YOUR_HARNESS_ID"
region: "us-west-2"
aws_profile: "deploy"
model_id: "global.anthropic.claude-opus-4-7"
min_reviewers: 3
max_reviewers: 5
max_review_rounds: 5
repos:
cli: "aws/agentcore-cli"
cdk: "aws/agentcore-l3-cdk-constructs"
Empty file added agents/core/__init__.py
Empty file.
30 changes: 30 additions & 0 deletions agents/core/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from dataclasses import dataclass

import yaml


@dataclass
class PipelineConfig:
harness_arn: str
region: str = "us-west-2"
data_plane_endpoint: str | None = None
aws_profile: str = "deploy"
model_id: str = "global.anthropic.claude-opus-4-7"
min_reviewers: int = 3
max_reviewers: int = 5
max_review_rounds: int = 5
cli_repo: str = "aws/agentcore-cli"
cdk_repo: str = "aws/agentcore-l3-cdk-constructs"

@classmethod
def from_yaml(cls, path: str) -> "PipelineConfig":
with open(path) as f:
data = yaml.safe_load(f)

repos = data.pop("repos", {})
if "cli" in repos:
data["cli_repo"] = repos["cli"]
if "cdk" in repos:
data["cdk_repo"] = repos["cdk"]

return cls(**{k: v for k, v in data.items() if k in cls.__dataclass_fields__})
Loading
Loading