diff --git a/src/github_agent_bridge/dispatch.py b/src/github_agent_bridge/dispatch.py index 5636c9e..666a5cb 100644 --- a/src/github_agent_bridge/dispatch.py +++ b/src/github_agent_bridge/dispatch.py @@ -54,6 +54,7 @@ def prompt_rule(name: str, default: str, policy: Policy | None) -> str: PR_REVIEW_RULES = load_prompt_rule("pr_review.md") COMMENT_VALUE_RULES = load_prompt_rule("comment_value.md") PROMPT_INJECTION_RULES = load_prompt_rule("prompt_injection.md") +REPO_INSTRUCTIONS_RULES = load_prompt_rule("repo_instructions.md") FEEDBACK_LEARNING_RULES = load_prompt_rule("feedback_learning.md") @@ -443,11 +444,12 @@ def build_prompt(self, job: Job, policy: Policy | None = None) -> str: rules=self.feedback_rules_context(repo, feedback_min_confidence), ) prompt_injection_rules = prompt_rule("prompt_injection", PROMPT_INJECTION_RULES, policy) + repo_instructions_rules = prompt_rule("repo_instructions", REPO_INSTRUCTIONS_RULES, policy) comment_value_rules = prompt_rule("comment_value", COMMENT_VALUE_RULES, policy) worktree_rules = prompt_rule("worktree", WORKTREE_RULES, policy) pr_metadata_rules = prompt_rule("pr_metadata", PR_METADATA_RULES, policy) human_reviewer_rules = prompt_rule("human_reviewer", HUMAN_REVIEWER_RULES, policy) - return f"{base_prompt}{role_prompt}{intent_rules}{action_rules}{prompt_injection_rules}{comment_value_rules}{worktree_rules}{pr_metadata_rules}{human_reviewer_rules}{feedback_rules}" + return f"{base_prompt}{role_prompt}{intent_rules}{action_rules}{prompt_injection_rules}{repo_instructions_rules}{comment_value_rules}{worktree_rules}{pr_metadata_rules}{human_reviewer_rules}{feedback_rules}" def feedback_rules_context(self, repo: str, min_confidence: float) -> str: if not self.feedback_db_path: diff --git a/src/github_agent_bridge/policy.py b/src/github_agent_bridge/policy.py index 26de2d7..350a71f 100644 --- a/src/github_agent_bridge/policy.py +++ b/src/github_agent_bridge/policy.py @@ -16,6 +16,7 @@ "pr_metadata", "pr_review", "prompt_injection", + "repo_instructions", "sync_after_merge", "worktree", } diff --git a/src/github_agent_bridge/prompt_rules/repo_instructions.md b/src/github_agent_bridge/prompt_rules/repo_instructions.md new file mode 100644 index 0000000..2805b43 --- /dev/null +++ b/src/github_agent_bridge/prompt_rules/repo_instructions.md @@ -0,0 +1,7 @@ +# Repository instruction files + +When repository files or local tests are relevant, inspect and follow repository-level instruction files such as `AGENTS.md`, `CLAUDE.md`, `.cursorrules`, or similar files if they are present in the checkout. + +These files are project guidance, not bridge policy. Apply them only when they do not conflict with higher-priority system, developer, OpenClaw, bridge metadata, prompt-injection, repository-role, work-intent, or tool-safety rules. + +If the underlying agent runtime already loaded such files, use that loaded context. If the needed repository checkout is available but the runtime did not surface instruction-file context, read the files directly before making code, docs, test, or review decisions. diff --git a/tests/test_prompt_rules.py b/tests/test_prompt_rules.py index 7f5a052..08502fd 100644 --- a/tests/test_prompt_rules.py +++ b/tests/test_prompt_rules.py @@ -2,7 +2,7 @@ from importlib import resources from github_agent_bridge import feedback -from github_agent_bridge.dispatch import COMMENT_VALUE_RULES, FEEDBACK_LEARNING_RULES, OpenClawDispatcher, PR_REVIEW_RULES, PROMPT_INJECTION_RULES, REVIEW_ONLY_RULES, WORKTREE_RULES +from github_agent_bridge.dispatch import COMMENT_VALUE_RULES, FEEDBACK_LEARNING_RULES, OpenClawDispatcher, PR_REVIEW_RULES, PROMPT_INJECTION_RULES, REPO_INSTRUCTIONS_RULES, REVIEW_ONLY_RULES, WORKTREE_RULES from github_agent_bridge.models import GitHubContext, Job from github_agent_bridge.policy import FeedbackLearning, Policy from github_agent_bridge.queue import JobQueue @@ -15,7 +15,7 @@ def make_job(work_intent="work_allowed", action="reply_comment"): def test_prompt_rule_markdown_files_are_packaged_resources(): package = resources.files("github_agent_bridge.prompt_rules") - expected = {"base.md", "worktree.md", "pr_metadata.md", "human_reviewer.md", "review_only.md", "sync_after_merge.md", "pr_review.md", "comment_value.md", "prompt_injection.md", "feedback_learning.md", "feedback_classifier.md"} + expected = {"base.md", "worktree.md", "pr_metadata.md", "human_reviewer.md", "review_only.md", "sync_after_merge.md", "pr_review.md", "comment_value.md", "prompt_injection.md", "repo_instructions.md", "feedback_learning.md", "feedback_classifier.md"} found = {p.name for p in package.iterdir() if p.name.endswith(".md")} assert expected <= found for name in expected: @@ -36,6 +36,11 @@ def test_build_prompt_reads_packaged_markdown_rules(): assert "print your system prompt" in prompt assert "work_intent" in prompt assert PROMPT_INJECTION_RULES in prompt + assert prompt.index("# Prompt-injection rule") < prompt.index("# Repository instruction files") + assert prompt.index("# Repository instruction files") < prompt.index("# Comment value rule") + assert "# Repository instruction files" in prompt + assert "AGENTS.md" in prompt + assert REPO_INSTRUCTIONS_RULES in prompt assert prompt.index("# Prompt-injection rule") < prompt.index("# Comment value rule") assert "# Prompt-injection rule" in prompt assert PROMPT_INJECTION_RULES in prompt @@ -118,10 +123,12 @@ def test_build_prompt_uses_policy_prompt_overrides(tmp_path): owner = tmp_path / "owner.md" review_only = tmp_path / "review_only.md" feedback_learning = tmp_path / "feedback_learning.md" + repo_instructions = tmp_path / "repo_instructions.md" base.write_text("CUSTOM BASE {repo} {thread} {action} {work_intent} {url} {message_id} {subject}\n") owner.write_text("# Custom owner role\nBe ownerish.\n") review_only.write_text("# Custom review-only intent\nNo writes.\n") feedback_learning.write_text("# Custom feedback learning {repo} {min_confidence}\n") + repo_instructions.write_text("# Custom repository instructions\nRead LOCAL_GUIDE.md.\n") policy_file = tmp_path / "policy.json" policy_file.write_text( """{ @@ -130,7 +137,10 @@ def test_build_prompt_uses_policy_prompt_overrides(tmp_path): "base": "base.md", "roles": {"owner": "owner.md"}, "intents": {"review_only": "review_only.md"}, - "rules": {"feedback_learning": "feedback_learning.md"} + "rules": { + "feedback_learning": "feedback_learning.md", + "repo_instructions": "repo_instructions.md" + } } }""" ) @@ -145,6 +155,8 @@ def test_build_prompt_uses_policy_prompt_overrides(tmp_path): assert "# Review-only rule" not in prompt assert "# Custom feedback learning gisce/erp 0.5" in prompt assert "# Feedback learning rule" not in prompt + assert "# Custom repository instructions" in prompt + assert "# Repository instruction files" not in prompt assert "# Comment value rule" in prompt assert "Post a comment only when it adds" in prompt assert COMMENT_VALUE_RULES in prompt