From 2d5da34b3d3412f35c228a551e0ed6b2720d4327 Mon Sep 17 00:00:00 2001 From: aran-yogesh Date: Sun, 22 Feb 2026 22:01:21 -0800 Subject: [PATCH 1/4] feat: inject AGENTS.md into system prompt --- apps/agent/agent/prompt.py | 12 ++++++++++++ apps/agent/agent/server.py | 9 +++++++-- apps/agent/agent/utils/agents_md.py | 30 +++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 apps/agent/agent/utils/agents_md.py diff --git a/apps/agent/agent/prompt.py b/apps/agent/agent/prompt.py index 0e356ebd..ad94bfbf 100644 --- a/apps/agent/agent/prompt.py +++ b/apps/agent/agent/prompt.py @@ -4,6 +4,7 @@ You are operating in a **remote Linux sandbox** at `{working_dir}`. All code execution and file operations happen in this sandbox environment. +{agents_md_section} **Important:** - Use `{working_dir}` as your working directory for all operations @@ -72,9 +73,20 @@ def construct_system_prompt( working_dir: str, linear_project_id: str = "", linear_issue_number: str = "", + agents_md: str | None = None, ) -> str: + agents_md_section = "" + if agents_md: + agents_md_section = ( + "\nThe following text is pulled from the repository's AGENTS.md file. " + "It may contain specific instructions and guidelines for the agent.\n" + "\n" + f"{agents_md}\n" + "\n" + ) return SYSTEM_PROMPT.format( working_dir=working_dir, linear_project_id=linear_project_id or "", linear_issue_number=linear_issue_number or "", + agents_md_section=agents_md_section, ) diff --git a/apps/agent/agent/server.py b/apps/agent/agent/server.py index c5c97898..37007cc8 100644 --- a/apps/agent/agent/server.py +++ b/apps/agent/agent/server.py @@ -42,6 +42,7 @@ SANDBOX_CREATING = "__creating__" SANDBOX_CREATION_TIMEOUT = 180 SANDBOX_POLL_INTERVAL = 1.0 +from .utils.agents_md import read_agents_md_in_sandbox from .utils.github import ( git_has_uncommitted_changes, is_valid_git_repo, @@ -136,8 +137,10 @@ async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915 logger.exception("Failed to restore clean remote URL") raise - logger.info("Repo updated at %s", repo_dir) - return repo_dir + logger.info("Repo updated at %s", repo_dir) + return repo_dir + + logger.info("Cloning repo %s/%s to %s", owner, repo, repo_dir) try: @@ -327,6 +330,7 @@ async def get_agent(config: RunnableConfig) -> Pregel: # noqa: PLR0915 linear_issue = config["configurable"].get("linear_issue", {}) linear_project_id = linear_issue.get("linear_project_id", "") linear_issue_number = linear_issue.get("linear_issue_number", "") + agents_md = await read_agents_md_in_sandbox(sandbox_backend, repo_dir) logger.info("Returning agent with sandbox for thread %s", thread_id) return create_deep_agent( @@ -335,6 +339,7 @@ async def get_agent(config: RunnableConfig) -> Pregel: # noqa: PLR0915 repo_dir, linear_project_id=linear_project_id, linear_issue_number=linear_issue_number, + agents_md=agents_md, ), tools=[http_request, fetch_url, commit_and_open_pr], backend=sandbox_backend, diff --git a/apps/agent/agent/utils/agents_md.py b/apps/agent/agent/utils/agents_md.py new file mode 100644 index 00000000..3d7ef45b --- /dev/null +++ b/apps/agent/agent/utils/agents_md.py @@ -0,0 +1,30 @@ +"""Helpers for reading agent instructions from AGENTS.md.""" + +from __future__ import annotations + +import asyncio +import shlex + +from deepagents.backends.protocol import SandboxBackendProtocol + + +async def read_agents_md_in_sandbox( + sandbox_backend: SandboxBackendProtocol, + repo_dir: str | None, +) -> str | None: + """Read AGENTS.md from the repo root if it exists.""" + if not repo_dir: + return None + + safe_agents_path = shlex.quote(f"{repo_dir}/AGENTS.md") + loop = asyncio.get_event_loop() + result = await loop.run_in_executor( + None, + sandbox_backend.execute, + f"test -f {safe_agents_path} && cat {safe_agents_path}", + ) + if result.exit_code != 0: + return None + content = result.output or "" + content = content.strip() + return content or None From 66bd62b69bc873ea4e1f51f8ef936f4de07e02a5 Mon Sep 17 00:00:00 2001 From: aran-yogesh Date: Mon, 23 Feb 2026 13:13:54 -0800 Subject: [PATCH 2/4] feat: add AGENTS.md support and fix repo cloning --- apps/agent/agent/server.py | 8 +++----- apps/agent/agent/utils/agents_md.py | 6 ++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/agent/agent/server.py b/apps/agent/agent/server.py index 37007cc8..1dad6586 100644 --- a/apps/agent/agent/server.py +++ b/apps/agent/agent/server.py @@ -137,11 +137,10 @@ async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915 logger.exception("Failed to restore clean remote URL") raise - logger.info("Repo updated at %s", repo_dir) - return repo_dir - - + logger.info("Repo updated at %s", repo_dir) + return repo_dir + # If we reach here, repo doesn't exist or is invalid - clone it logger.info("Cloning repo %s/%s to %s", owner, repo, repo_dir) try: result = await loop.run_in_executor( @@ -218,7 +217,6 @@ async def get_agent(config: RunnableConfig) -> Pregel: # noqa: PLR0915 encrypted_token = config["configurable"].get("github_token_encrypted") if encrypted_token: github_token = decrypt_token(encrypted_token) - logger.debug("Decrypted GitHub token") if thread_id is None or not graph_loaded_for_execution(config): logger.info("No thread_id or not for execution, returning agent without sandbox") diff --git a/apps/agent/agent/utils/agents_md.py b/apps/agent/agent/utils/agents_md.py index 3d7ef45b..715de9f9 100644 --- a/apps/agent/agent/utils/agents_md.py +++ b/apps/agent/agent/utils/agents_md.py @@ -3,10 +3,13 @@ from __future__ import annotations import asyncio +import logging import shlex from deepagents.backends.protocol import SandboxBackendProtocol +logger = logging.getLogger(__name__) + async def read_agents_md_in_sandbox( sandbox_backend: SandboxBackendProtocol, @@ -24,7 +27,10 @@ async def read_agents_md_in_sandbox( f"test -f {safe_agents_path} && cat {safe_agents_path}", ) if result.exit_code != 0: + logger.debug("AGENTS.md not found at %s", safe_agents_path) return None content = result.output or "" content = content.strip() + if content: + logger.info("Loaded AGENTS.md from %s", safe_agents_path) return content or None From b8f5b735e2b61c3c7753ae2a740e41631f10573d Mon Sep 17 00:00:00 2001 From: aran-yogesh Date: Mon, 23 Feb 2026 16:52:15 -0800 Subject: [PATCH 3/4] address review comments on AGENTS.md injection --- apps/agent/agent/prompt.py | 2 +- apps/agent/agent/server.py | 5 ++++- apps/agent/agent/utils/agents_md.py | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/agent/agent/prompt.py b/apps/agent/agent/prompt.py index ad94bfbf..85adab26 100644 --- a/apps/agent/agent/prompt.py +++ b/apps/agent/agent/prompt.py @@ -73,7 +73,7 @@ def construct_system_prompt( working_dir: str, linear_project_id: str = "", linear_issue_number: str = "", - agents_md: str | None = None, + agents_md: str = "", ) -> str: agents_md_section = "" if agents_md: diff --git a/apps/agent/agent/server.py b/apps/agent/agent/server.py index 1dad6586..eb297579 100644 --- a/apps/agent/agent/server.py +++ b/apps/agent/agent/server.py @@ -140,7 +140,6 @@ async def _clone_or_pull_repo_in_sandbox( # noqa: PLR0915 logger.info("Repo updated at %s", repo_dir) return repo_dir - # If we reach here, repo doesn't exist or is invalid - clone it logger.info("Cloning repo %s/%s to %s", owner, repo, repo_dir) try: result = await loop.run_in_executor( @@ -325,6 +324,10 @@ async def get_agent(config: RunnableConfig) -> Pregel: # noqa: PLR0915 SANDBOX_BACKENDS[thread_id] = sandbox_backend + if not repo_dir: + msg = "repo_dir is not defined; cannot operate without a cloned repository" + raise RuntimeError(msg) + linear_issue = config["configurable"].get("linear_issue", {}) linear_project_id = linear_issue.get("linear_project_id", "") linear_issue_number = linear_issue.get("linear_issue_number", "") diff --git a/apps/agent/agent/utils/agents_md.py b/apps/agent/agent/utils/agents_md.py index 715de9f9..6afd63e7 100644 --- a/apps/agent/agent/utils/agents_md.py +++ b/apps/agent/agent/utils/agents_md.py @@ -31,6 +31,4 @@ async def read_agents_md_in_sandbox( return None content = result.output or "" content = content.strip() - if content: - logger.info("Loaded AGENTS.md from %s", safe_agents_path) return content or None From 31adfd0bd45385bb1074c6ec4379d5157a8e5573 Mon Sep 17 00:00:00 2001 From: aran-yogesh Date: Mon, 23 Feb 2026 17:16:30 -0800 Subject: [PATCH 4/4] update error message --- apps/agent/agent/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/agent/agent/server.py b/apps/agent/agent/server.py index eb297579..ea0bca67 100644 --- a/apps/agent/agent/server.py +++ b/apps/agent/agent/server.py @@ -325,7 +325,7 @@ async def get_agent(config: RunnableConfig) -> Pregel: # noqa: PLR0915 SANDBOX_BACKENDS[thread_id] = sandbox_backend if not repo_dir: - msg = "repo_dir is not defined; cannot operate without a cloned repository" + msg = "Cannot proceed: no repo was cloned. Set 'repo.owner' and 'repo.name' in the configurable config" raise RuntimeError(msg) linear_issue = config["configurable"].get("linear_issue", {})