diff --git a/README.md b/README.md index f509fd6e..83aa6cc3 100644 --- a/README.md +++ b/README.md @@ -354,8 +354,12 @@ For example, when using `uvx`, you would run claude mcp add serena -- uvx --from git+https://github.com/oraios/serena serena-mcp-server --context ide-assistant --project $(pwd) ``` -ℹ️ Once in Claude Code, run `/mcp__serena__initial_instructions` to load instructions for using Serena's tools. Run this command -whenever you start a new conversation and after any compacting operation to ensure Claude remains properly configured to use Serena's tools. +ℹ️ Serena comes with an instruction text, and Claude needs to read it to properly use Serena's tools. + Once in Claude Code, you can ask to "read Serena's initial instructions" or run `/mcp__serena__initial_instructions` to load the instruction text. + Do this whenever you start a new conversation and after any compacting operation to ensure Claude remains properly configured to use Serena's tools. + +ℹ️ **NEW**: an alternative to the above is adding the instructions as part of the system prompt, then you will not need to run the command above or to remember re-running it after compacting. + This can be achieved through starting claude code with `claude --append-system-prompt $(uvx --from git+https://github.com/oraios/serena print-system-prompt)`. Note that this is **experimental**, Claude may not understand the instructions correctly in this way, and we haven't thoroughly tested the resulting behavior. Please report any issues you encounter. ### Claude Desktop diff --git a/pyproject.toml b/pyproject.toml index 24ba0412..c0c4c813 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ dependencies = [ [project.scripts] serena-mcp-server = "serena.mcp:start_mcp_server" index-project = "serena.agent:index_project" +print-system-prompt = "serena.agent:print_system_prompt" [project.license] text = "MIT" diff --git a/src/serena/agent.py b/src/serena/agent.py index 454986f4..ac24417f 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -124,6 +124,39 @@ def index_project(project: str, log_level: str = "INFO") -> None: print(f"Symbols saved to {ls.cache_path}") +@click.command() +@click.argument("project", type=click.Path(exists=True), required=False, default=os.getcwd()) +@click.option("--log-level", type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]), default="WARNING") +@click.option( + "--only-instructions", + is_flag=True, + help="If set, only print the initial instructions prompt (without prefix or postfix). The prefix and postfix are small additions that are used to" + "make the initial instructions more digestible for an LLM in the context of a system prompt, as opposed to their normal usage within a conversation.", +) +def print_system_prompt(project: str, log_level: str = "WARNING", only_instructions: bool = False) -> None: + """ + Print the system prompt (initial instructions with a potential pre/post-fix) for a project. + """ + prefix_to_instructions_prompt = ( + "You will receive access to Serena's symbolic tools. Below are instructions for using them, take them into account." + ) + postfix_to_instructions_prompt = "You begin the conversation by acknowledging that you understood the above instructions on the symbolic tools and are ready to receive a task. You will not need to call the tool on getting initial instructions." + + from serena.tools.workflow_tools import InitialInstructionsTool + + log_level_int = logging.getLevelNamesMapping()[log_level.upper()] + logging.configure(level=log_level_int) + + agent = SerenaAgent(project=os.path.abspath(project), serena_config=SerenaConfig(web_dashboard=False, log_level=log_level_int)) + initial_instructions_tool = agent.get_tool(InitialInstructionsTool) + initial_instructions = initial_instructions_tool.apply() + if only_instructions: + print(initial_instructions) + else: + system_prompt = f"{prefix_to_instructions_prompt}\n{initial_instructions}\n{postfix_to_instructions_prompt}" + print(system_prompt) + + class SerenaAgent: def __init__( self, diff --git a/src/serena/tools/workflow_tools.py b/src/serena/tools/workflow_tools.py index 2c09a202..6172cc33 100644 --- a/src/serena/tools/workflow_tools.py +++ b/src/serena/tools/workflow_tools.py @@ -132,8 +132,8 @@ class InitialInstructionsTool(Tool, ToolMarkerDoesNotRequireActiveProject): def apply(self) -> str: """ Get the initial instructions for the current coding project. - You should always call this tool before starting to work (including using any other tool) on any programming task! - The only exception is when a user asks you to activate a project, in which case you should call the `activate_project` first - instead and then call this tool. + If you haven't received instructions on how to use Serena's tools in the system prompt, + you should always call this tool before starting to work (including using any other tool) on any programming task, + the only exception being when you are asked to call `activate_project`, which you should then call before. """ return self.agent.create_system_prompt()