#
tokens: 49426/50000 190/348 files (page 1/14)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 14. Use http://codebase.md/oraios/serena?page={x} to view the full context.

# Directory Structure

```
├── .devcontainer
│   └── devcontainer.json
├── .dockerignore
├── .env.example
├── .github
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── config.yml
│   │   ├── feature_request.md
│   │   └── issue--bug--performance-problem--question-.md
│   └── workflows
│       ├── codespell.yml
│       ├── docker.yml
│       ├── docs.yaml
│       ├── junie.yml
│       ├── publish.yml
│       └── pytest.yml
├── .gitignore
├── .serena
│   ├── .gitignore
│   ├── memories
│   │   ├── adding_new_language_support_guide.md
│   │   ├── serena_core_concepts_and_architecture.md
│   │   ├── serena_repository_structure.md
│   │   └── suggested_commands.md
│   └── project.yml
├── .vscode
│   └── settings.json
├── CHANGELOG.md
├── CLAUDE.md
├── compose.yaml
├── CONTRIBUTING.md
├── docker_build_and_run.sh
├── DOCKER.md
├── Dockerfile
├── docs
│   ├── _config.yml
│   ├── .gitignore
│   ├── 01-about
│   │   ├── 000_intro.md
│   │   ├── 010_llm-integration.md
│   │   ├── 020_programming-languages.md
│   │   ├── 030_serena-in-action.md
│   │   ├── 035_tools.md
│   │   ├── 040_comparison-to-other-agents.md
│   │   └── 050_acknowledgements.md
│   ├── 02-usage
│   │   ├── 000_intro.md
│   │   ├── 010_prerequisites.md
│   │   ├── 020_running.md
│   │   ├── 030_clients.md
│   │   ├── 040_workflow.md
│   │   ├── 050_configuration.md
│   │   ├── 060_dashboard.md
│   │   ├── 070_security.md
│   │   └── 999_additional-usage.md
│   ├── 03-special-guides
│   │   ├── 000_intro.md
│   │   ├── custom_agent.md
│   │   ├── scala_setup_guide_for_serena.md
│   │   └── serena_on_chatgpt.md
│   ├── autogen_rst.py
│   ├── create_toc.py
│   └── index.md
├── flake.lock
├── flake.nix
├── lessons_learned.md
├── LICENSE
├── llms-install.md
├── public
│   └── .gitignore
├── pyproject.toml
├── README.md
├── repo_dir_sync.py
├── resources
│   ├── serena-icons.cdr
│   ├── serena-logo-dark-mode.svg
│   ├── serena-logo.cdr
│   ├── serena-logo.svg
│   └── vscode_sponsor_logo.png
├── roadmap.md
├── scripts
│   ├── agno_agent.py
│   ├── demo_run_tools.py
│   ├── gen_prompt_factory.py
│   ├── mcp_server.py
│   ├── print_mode_context_options.py
│   ├── print_tool_overview.py
│   └── profile_tool_call.py
├── src
│   ├── interprompt
│   │   ├── __init__.py
│   │   ├── .syncCommitId.remote
│   │   ├── .syncCommitId.this
│   │   ├── jinja_template.py
│   │   ├── multilang_prompt.py
│   │   ├── prompt_factory.py
│   │   └── util
│   │       ├── __init__.py
│   │       └── class_decorators.py
│   ├── README.md
│   ├── serena
│   │   ├── __init__.py
│   │   ├── agent.py
│   │   ├── agno.py
│   │   ├── analytics.py
│   │   ├── cli.py
│   │   ├── code_editor.py
│   │   ├── config
│   │   │   ├── __init__.py
│   │   │   ├── context_mode.py
│   │   │   └── serena_config.py
│   │   ├── constants.py
│   │   ├── dashboard.py
│   │   ├── generated
│   │   │   └── generated_prompt_factory.py
│   │   ├── gui_log_viewer.py
│   │   ├── ls_manager.py
│   │   ├── mcp.py
│   │   ├── project.py
│   │   ├── prompt_factory.py
│   │   ├── resources
│   │   │   ├── config
│   │   │   │   ├── contexts
│   │   │   │   │   ├── agent.yml
│   │   │   │   │   ├── chatgpt.yml
│   │   │   │   │   ├── codex.yml
│   │   │   │   │   ├── context.template.yml
│   │   │   │   │   ├── desktop-app.yml
│   │   │   │   │   ├── ide-assistant.yml
│   │   │   │   │   └── oaicompat-agent.yml
│   │   │   │   ├── internal_modes
│   │   │   │   │   └── jetbrains.yml
│   │   │   │   ├── modes
│   │   │   │   │   ├── editing.yml
│   │   │   │   │   ├── interactive.yml
│   │   │   │   │   ├── mode.template.yml
│   │   │   │   │   ├── no-onboarding.yml
│   │   │   │   │   ├── onboarding.yml
│   │   │   │   │   ├── one-shot.yml
│   │   │   │   │   └── planning.yml
│   │   │   │   └── prompt_templates
│   │   │   │       ├── simple_tool_outputs.yml
│   │   │   │       └── system_prompt.yml
│   │   │   ├── dashboard
│   │   │   │   ├── dashboard.css
│   │   │   │   ├── dashboard.js
│   │   │   │   ├── index.html
│   │   │   │   ├── jquery.min.js
│   │   │   │   ├── serena-icon-16.png
│   │   │   │   ├── serena-icon-32.png
│   │   │   │   ├── serena-icon-48.png
│   │   │   │   ├── serena-logo-dark-mode.svg
│   │   │   │   ├── serena-logo.svg
│   │   │   │   ├── serena-logs-dark-mode.png
│   │   │   │   └── serena-logs.png
│   │   │   ├── project.template.yml
│   │   │   └── serena_config.template.yml
│   │   ├── symbol.py
│   │   ├── task_executor.py
│   │   ├── text_utils.py
│   │   ├── tools
│   │   │   ├── __init__.py
│   │   │   ├── cmd_tools.py
│   │   │   ├── config_tools.py
│   │   │   ├── file_tools.py
│   │   │   ├── jetbrains_plugin_client.py
│   │   │   ├── jetbrains_tools.py
│   │   │   ├── memory_tools.py
│   │   │   ├── symbol_tools.py
│   │   │   ├── tools_base.py
│   │   │   └── workflow_tools.py
│   │   └── util
│   │       ├── class_decorators.py
│   │       ├── cli_util.py
│   │       ├── exception.py
│   │       ├── file_system.py
│   │       ├── general.py
│   │       ├── git.py
│   │       ├── inspection.py
│   │       ├── logging.py
│   │       ├── shell.py
│   │       └── thread.py
│   └── solidlsp
│       ├── __init__.py
│       ├── .gitignore
│       ├── language_servers
│       │   ├── al_language_server.py
│       │   ├── bash_language_server.py
│       │   ├── clangd_language_server.py
│       │   ├── clojure_lsp.py
│       │   ├── common.py
│       │   ├── csharp_language_server.py
│       │   ├── dart_language_server.py
│       │   ├── eclipse_jdtls.py
│       │   ├── elixir_tools
│       │   │   ├── __init__.py
│       │   │   ├── elixir_tools.py
│       │   │   └── README.md
│       │   ├── elm_language_server.py
│       │   ├── erlang_language_server.py
│       │   ├── fortran_language_server.py
│       │   ├── gopls.py
│       │   ├── haskell_language_server.py
│       │   ├── intelephense.py
│       │   ├── jedi_server.py
│       │   ├── julia_server.py
│       │   ├── kotlin_language_server.py
│       │   ├── lua_ls.py
│       │   ├── marksman.py
│       │   ├── nixd_ls.py
│       │   ├── omnisharp
│       │   │   ├── initialize_params.json
│       │   │   ├── runtime_dependencies.json
│       │   │   └── workspace_did_change_configuration.json
│       │   ├── omnisharp.py
│       │   ├── perl_language_server.py
│       │   ├── pyright_server.py
│       │   ├── r_language_server.py
│       │   ├── regal_server.py
│       │   ├── ruby_lsp.py
│       │   ├── rust_analyzer.py
│       │   ├── scala_language_server.py
│       │   ├── solargraph.py
│       │   ├── sourcekit_lsp.py
│       │   ├── terraform_ls.py
│       │   ├── typescript_language_server.py
│       │   ├── vts_language_server.py
│       │   ├── yaml_language_server.py
│       │   └── zls.py
│       ├── ls_config.py
│       ├── ls_exceptions.py
│       ├── ls_handler.py
│       ├── ls_request.py
│       ├── ls_types.py
│       ├── ls_utils.py
│       ├── ls.py
│       ├── lsp_protocol_handler
│       │   ├── lsp_constants.py
│       │   ├── lsp_requests.py
│       │   ├── lsp_types.py
│       │   └── server.py
│       ├── settings.py
│       └── util
│           ├── cache.py
│           ├── subprocess_util.py
│           └── zip.py
├── sync.py
├── test
│   ├── __init__.py
│   ├── conftest.py
│   ├── resources
│   │   └── repos
│   │       ├── al
│   │       │   └── test_repo
│   │       │       ├── app.json
│   │       │       └── src
│   │       │           ├── Codeunits
│   │       │           │   ├── CustomerMgt.Codeunit.al
│   │       │           │   └── PaymentProcessorImpl.Codeunit.al
│   │       │           ├── Enums
│   │       │           │   └── CustomerType.Enum.al
│   │       │           ├── Interfaces
│   │       │           │   └── IPaymentProcessor.Interface.al
│   │       │           ├── Pages
│   │       │           │   ├── CustomerCard.Page.al
│   │       │           │   └── CustomerList.Page.al
│   │       │           ├── TableExtensions
│   │       │           │   └── Item.TableExt.al
│   │       │           └── Tables
│   │       │               └── Customer.Table.al
│   │       ├── bash
│   │       │   └── test_repo
│   │       │       ├── config.sh
│   │       │       ├── main.sh
│   │       │       └── utils.sh
│   │       ├── clojure
│   │       │   └── test_repo
│   │       │       ├── deps.edn
│   │       │       └── src
│   │       │           └── test_app
│   │       │               ├── core.clj
│   │       │               └── utils.clj
│   │       ├── csharp
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── Models
│   │       │       │   └── Person.cs
│   │       │       ├── Program.cs
│   │       │       ├── serena.sln
│   │       │       └── TestProject.csproj
│   │       ├── dart
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── lib
│   │       │       │   ├── helper.dart
│   │       │       │   ├── main.dart
│   │       │       │   └── models.dart
│   │       │       └── pubspec.yaml
│   │       ├── elixir
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── lib
│   │       │       │   ├── examples.ex
│   │       │       │   ├── ignored_dir
│   │       │       │   │   └── ignored_module.ex
│   │       │       │   ├── models.ex
│   │       │       │   ├── services.ex
│   │       │       │   ├── test_repo.ex
│   │       │       │   └── utils.ex
│   │       │       ├── mix.exs
│   │       │       ├── mix.lock
│   │       │       ├── scripts
│   │       │       │   └── build_script.ex
│   │       │       └── test
│   │       │           ├── models_test.exs
│   │       │           └── test_repo_test.exs
│   │       ├── elm
│   │       │   └── test_repo
│   │       │       ├── elm.json
│   │       │       ├── Main.elm
│   │       │       └── Utils.elm
│   │       ├── erlang
│   │       │   └── test_repo
│   │       │       ├── hello.erl
│   │       │       ├── ignored_dir
│   │       │       │   └── ignored_module.erl
│   │       │       ├── include
│   │       │       │   ├── records.hrl
│   │       │       │   └── types.hrl
│   │       │       ├── math_utils.erl
│   │       │       ├── rebar.config
│   │       │       ├── src
│   │       │       │   ├── app.erl
│   │       │       │   ├── models.erl
│   │       │       │   ├── services.erl
│   │       │       │   └── utils.erl
│   │       │       └── test
│   │       │           ├── models_tests.erl
│   │       │           └── utils_tests.erl
│   │       ├── fortran
│   │       │   └── test_repo
│   │       │       ├── main.f90
│   │       │       └── modules
│   │       │           ├── geometry.f90
│   │       │           └── math_utils.f90
│   │       ├── go
│   │       │   └── test_repo
│   │       │       └── main.go
│   │       ├── haskell
│   │       │   └── test_repo
│   │       │       ├── app
│   │       │       │   └── Main.hs
│   │       │       ├── haskell-test-repo.cabal
│   │       │       ├── package.yaml
│   │       │       ├── src
│   │       │       │   ├── Calculator.hs
│   │       │       │   └── Helper.hs
│   │       │       └── stack.yaml
│   │       ├── java
│   │       │   └── test_repo
│   │       │       ├── pom.xml
│   │       │       └── src
│   │       │           └── main
│   │       │               └── java
│   │       │                   └── test_repo
│   │       │                       ├── Main.java
│   │       │                       ├── Model.java
│   │       │                       ├── ModelUser.java
│   │       │                       └── Utils.java
│   │       ├── julia
│   │       │   └── test_repo
│   │       │       ├── lib
│   │       │       │   └── helper.jl
│   │       │       └── main.jl
│   │       ├── kotlin
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── build.gradle.kts
│   │       │       └── src
│   │       │           └── main
│   │       │               └── kotlin
│   │       │                   └── test_repo
│   │       │                       ├── Main.kt
│   │       │                       ├── Model.kt
│   │       │                       ├── ModelUser.kt
│   │       │                       └── Utils.kt
│   │       ├── lua
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── main.lua
│   │       │       ├── src
│   │       │       │   ├── calculator.lua
│   │       │       │   └── utils.lua
│   │       │       └── tests
│   │       │           └── test_calculator.lua
│   │       ├── markdown
│   │       │   └── test_repo
│   │       │       ├── api.md
│   │       │       ├── CONTRIBUTING.md
│   │       │       ├── guide.md
│   │       │       └── README.md
│   │       ├── nix
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── default.nix
│   │       │       ├── flake.nix
│   │       │       ├── lib
│   │       │       │   └── utils.nix
│   │       │       ├── modules
│   │       │       │   └── example.nix
│   │       │       └── scripts
│   │       │           └── hello.sh
│   │       ├── perl
│   │       │   └── test_repo
│   │       │       ├── helper.pl
│   │       │       └── main.pl
│   │       ├── php
│   │       │   └── test_repo
│   │       │       ├── helper.php
│   │       │       ├── index.php
│   │       │       └── simple_var.php
│   │       ├── python
│   │       │   └── test_repo
│   │       │       ├── .gitignore
│   │       │       ├── custom_test
│   │       │       │   ├── __init__.py
│   │       │       │   └── advanced_features.py
│   │       │       ├── examples
│   │       │       │   ├── __init__.py
│   │       │       │   └── user_management.py
│   │       │       ├── ignore_this_dir_with_postfix
│   │       │       │   └── ignored_module.py
│   │       │       ├── scripts
│   │       │       │   ├── __init__.py
│   │       │       │   └── run_app.py
│   │       │       └── test_repo
│   │       │           ├── __init__.py
│   │       │           ├── complex_types.py
│   │       │           ├── models.py
│   │       │           ├── name_collisions.py
│   │       │           ├── nested_base.py
│   │       │           ├── nested.py
│   │       │           ├── overloaded.py
│   │       │           ├── services.py
│   │       │           ├── utils.py
│   │       │           └── variables.py
│   │       ├── r
│   │       │   └── test_repo
│   │       │       ├── .Rbuildignore
│   │       │       ├── DESCRIPTION
│   │       │       ├── examples
│   │       │       │   └── analysis.R
│   │       │       ├── NAMESPACE
│   │       │       └── R
│   │       │           ├── models.R
│   │       │           └── utils.R
│   │       ├── rego
│   │       │   └── test_repo
│   │       │       ├── policies
│   │       │       │   ├── authz.rego
│   │       │       │   └── validation.rego
│   │       │       └── utils
│   │       │           └── helpers.rego
│   │       ├── ruby
│   │       │   └── test_repo
│   │       │       ├── .solargraph.yml
│   │       │       ├── examples
│   │       │       │   └── user_management.rb
│   │       │       ├── lib.rb
│   │       │       ├── main.rb
│   │       │       ├── models.rb
│   │       │       ├── nested.rb
│   │       │       ├── services.rb
│   │       │       └── variables.rb
│   │       ├── rust
│   │       │   ├── test_repo
│   │       │   │   ├── Cargo.lock
│   │       │   │   ├── Cargo.toml
│   │       │   │   └── src
│   │       │   │       ├── lib.rs
│   │       │   │       └── main.rs
│   │       │   └── test_repo_2024
│   │       │       ├── Cargo.lock
│   │       │       ├── Cargo.toml
│   │       │       └── src
│   │       │           ├── lib.rs
│   │       │           └── main.rs
│   │       ├── scala
│   │       │   ├── build.sbt
│   │       │   ├── project
│   │       │   │   ├── build.properties
│   │       │   │   ├── metals.sbt
│   │       │   │   └── plugins.sbt
│   │       │   └── src
│   │       │       └── main
│   │       │           └── scala
│   │       │               └── com
│   │       │                   └── example
│   │       │                       ├── Main.scala
│   │       │                       └── Utils.scala
│   │       ├── swift
│   │       │   └── test_repo
│   │       │       ├── Package.swift
│   │       │       └── src
│   │       │           ├── main.swift
│   │       │           └── utils.swift
│   │       ├── terraform
│   │       │   └── test_repo
│   │       │       ├── data.tf
│   │       │       ├── main.tf
│   │       │       ├── outputs.tf
│   │       │       └── variables.tf
│   │       ├── typescript
│   │       │   └── test_repo
│   │       │       ├── .serena
│   │       │       │   └── project.yml
│   │       │       ├── index.ts
│   │       │       ├── tsconfig.json
│   │       │       └── use_helper.ts
│   │       ├── yaml
│   │       │   └── test_repo
│   │       │       ├── config.yaml
│   │       │       ├── data.yaml
│   │       │       └── services.yml
│   │       └── zig
│   │           └── test_repo
│   │               ├── .gitignore
│   │               ├── build.zig
│   │               ├── src
│   │               │   ├── calculator.zig
│   │               │   ├── main.zig
│   │               │   └── math_utils.zig
│   │               └── zls.json
│   ├── serena
│   │   ├── __init__.py
│   │   ├── __snapshots__
│   │   │   └── test_symbol_editing.ambr
│   │   ├── config
│   │   │   ├── __init__.py
│   │   │   └── test_serena_config.py
│   │   ├── test_cli_project_commands.py
│   │   ├── test_edit_marker.py
│   │   ├── test_mcp.py
│   │   ├── test_serena_agent.py
│   │   ├── test_symbol_editing.py
│   │   ├── test_symbol.py
│   │   ├── test_task_executor.py
│   │   ├── test_text_utils.py
│   │   ├── test_tool_parameter_types.py
│   │   └── util
│   │       ├── test_exception.py
│   │       └── test_file_system.py
│   └── solidlsp
│       ├── al
│       │   └── test_al_basic.py
│       ├── bash
│       │   ├── __init__.py
│       │   └── test_bash_basic.py
│       ├── clojure
│       │   ├── __init__.py
│       │   └── test_clojure_basic.py
│       ├── csharp
│       │   └── test_csharp_basic.py
│       ├── dart
│       │   ├── __init__.py
│       │   └── test_dart_basic.py
│       ├── elixir
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_elixir_basic.py
│       │   ├── test_elixir_ignored_dirs.py
│       │   ├── test_elixir_integration.py
│       │   └── test_elixir_symbol_retrieval.py
│       ├── elm
│       │   └── test_elm_basic.py
│       ├── erlang
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_erlang_basic.py
│       │   ├── test_erlang_ignored_dirs.py
│       │   └── test_erlang_symbol_retrieval.py
│       ├── fortran
│       │   ├── __init__.py
│       │   └── test_fortran_basic.py
│       ├── go
│       │   └── test_go_basic.py
│       ├── haskell
│       │   ├── __init__.py
│       │   └── test_haskell_basic.py
│       ├── java
│       │   └── test_java_basic.py
│       ├── julia
│       │   └── test_julia_basic.py
│       ├── kotlin
│       │   └── test_kotlin_basic.py
│       ├── lua
│       │   └── test_lua_basic.py
│       ├── markdown
│       │   ├── __init__.py
│       │   └── test_markdown_basic.py
│       ├── nix
│       │   └── test_nix_basic.py
│       ├── perl
│       │   └── test_perl_basic.py
│       ├── php
│       │   └── test_php_basic.py
│       ├── python
│       │   ├── test_python_basic.py
│       │   ├── test_retrieval_with_ignored_dirs.py
│       │   └── test_symbol_retrieval.py
│       ├── r
│       │   ├── __init__.py
│       │   └── test_r_basic.py
│       ├── rego
│       │   └── test_rego_basic.py
│       ├── ruby
│       │   ├── test_ruby_basic.py
│       │   └── test_ruby_symbol_retrieval.py
│       ├── rust
│       │   ├── test_rust_2024_edition.py
│       │   └── test_rust_basic.py
│       ├── scala
│       │   └── test_scala_language_server.py
│       ├── swift
│       │   └── test_swift_basic.py
│       ├── terraform
│       │   └── test_terraform_basic.py
│       ├── typescript
│       │   └── test_typescript_basic.py
│       ├── util
│       │   └── test_zip.py
│       ├── yaml_ls
│       │   ├── __init__.py
│       │   └── test_yaml_basic.py
│       └── zig
│           └── test_zig_basic.py
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/public/.gitignore:
--------------------------------------------------------------------------------

```

```

--------------------------------------------------------------------------------
/test/resources/repos/elixir/test_repo/.gitignore:
--------------------------------------------------------------------------------

```

```

--------------------------------------------------------------------------------
/.serena/.gitignore:
--------------------------------------------------------------------------------

```
/cache

```

--------------------------------------------------------------------------------
/test/resources/repos/kotlin/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
.gradle/

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
ignore_this_dir*/
```

--------------------------------------------------------------------------------
/src/solidlsp/.gitignore:
--------------------------------------------------------------------------------

```
language_servers/static
```

--------------------------------------------------------------------------------
/test/resources/repos/r/test_repo/.Rbuildignore:
--------------------------------------------------------------------------------

```
^.*\.Rproj$
^\.Rproj\.user$
^\.serena$
```

--------------------------------------------------------------------------------
/src/interprompt/.syncCommitId.remote:
--------------------------------------------------------------------------------

```
059d50b7d4d7e8fb9e7a13df7f7f33bae1aed5e2
```

--------------------------------------------------------------------------------
/src/interprompt/.syncCommitId.this:
--------------------------------------------------------------------------------

```
53ee7f47c08f29ae336567bcfaf89f79e7d447a2
```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/.solargraph.yml:
--------------------------------------------------------------------------------

```yaml
---
include:
  - "main.rb"
  - "lib.rb"

```

--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------

```
/_toc.yml
/jupyter_execute
/conf.py
/_build

```

--------------------------------------------------------------------------------
/test/resources/repos/zig/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
zig-cache/
zig-out/
.zig-cache/
build/
dist/
```

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
GOOGLE_API_KEY=<your_google_api_key>
ANTHROPIC_API_KEY=<your_key>

```

--------------------------------------------------------------------------------
/test/resources/repos/nix/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
# Nix specific
result
result-*
.direnv/

# Build artifacts
*.drv

# IDE
.vscode/
.idea/
```

--------------------------------------------------------------------------------
/test/resources/repos/lua/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
# Lua specific
*.luac
.luarocks/
lua_modules/
luarocks/

# Build artifacts
build/
dist/

# IDE
.vscode/
.idea/
```

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
data
logs
log
test/log
docs/jupyter_execute
docs/.jupyter_cache
docs/_build
coverage.xml
docker_build_and_run.sh

```

--------------------------------------------------------------------------------
/test/resources/repos/csharp/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio temporary files
.vs/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# Files built by Visual Studio
*.user
*.userosscache
*.sln.docstates

# Build results
*.dll
*.exe
*.pdb

# NuGet
*.nupkg
*.snupkg
packages/
```

--------------------------------------------------------------------------------
/test/resources/repos/dart/test_repo/.gitignore:
--------------------------------------------------------------------------------

```
# Files and directories created by pub
.dart_tool/
.packages
pubspec.lock
build/

# If you're building an application, you may want to check-in your pubspec.lock
# pubspec.lock

# Directory created by dartdoc
doc/api/

# dotenv environment variables file
.env*

# Avoid committing generated Javascript files
*.dart.js
*.info.json      # Produced by the --dump-info flag.
*.js             # When generated by dart2js. Don't specify *.js if your
                 # project includes source files written in JavaScript.
*.js_
*.js.deps
*.js.map
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# macOS specific files
.DS_Store
.AppleDouble
.LSOverride
._*
.Spotlight-V100
.Trashes
Icon
.fseventsd
.DocumentRevisions-V100
.TemporaryItems
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Windows specific files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msix
*.msm
*.msp
*.lnk

# Linux specific files
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*

# IDE/Text Editors
# VS Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
.history/

# JetBrains IDEs (beyond .idea/)
*.iml
*.ipr
*.iws
out/
.idea_modules/

# Sublime Text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
*.sublime-project

# Project specific ignore
.idea
temp

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# reports
pylint.html
.pylint.d

# Serena-specific
/*.yml
!*.template.yml
/agent-ui
/test/**/.serena

# clojure-lsp temporary files
.calva/
.clj-kondo/
.cpcache/
.lsp/

# temporary and backup files
*.bak
*.tmp
tmp/

.vscode/

# Claude settings
.claude/settings.local.json

# Elixir
/test/resources/repos/elixir/test_repo/deps
# Exception: Don't ignore Elixir test repository lib directory (contains source code)
!/test/resources/repos/elixir/test_repo/lib

# Exception: Don't ignore Nix test repository lib directory (contains source code)
!/test/resources/repos/nix/test_repo/lib

# Exception: Don't ignore Julia test repository lib directory (contains source code)
!/test/resources/repos/julia/test_repo/lib

# Swift
/test/resources/repos/swift/test_repo/.build
/test/resources/repos/swift/test_repo/.swiftpm

# Elm
/test/resources/repos/elm/test_repo/.elm/
/test/resources/repos/elm/test_repo/elm-stuff/

# Scala
.metals/
.bsp/
.scala-build/
.bloop/
bootstrap
test/resources/repos/scala/.bloop/

# Haskell
.stack-work/
*.cabal
stack.yaml.lock
dist-newstyle/
cabal.project.local*
.ghc.environment.*
```

--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------

```markdown
Serena uses (modified) versions of other libraries/packages:

 * solidlsp (our fork of [microsoft/multilspy](https://github.com/microsoft/multilspy) for fully synchronous language server communication)
 * [interprompt](https://github.com/oraios/interprompt) (our prompt templating library)

```

--------------------------------------------------------------------------------
/test/resources/repos/markdown/test_repo/README.md:
--------------------------------------------------------------------------------

```markdown
# Test Repository

This is a test repository for markdown language server testing.

## Overview

This repository contains sample markdown files for testing LSP features.

## Features

- Document symbol detection
- Link navigation
- Reference finding
- Code completion

### Installation

To use this test repository:

1. Clone the repository
2. Install dependencies
3. Run tests

### Usage

See [guide.md](guide.md) for detailed usage instructions.

## Code Examples

Here's a simple example:

```python
def hello_world():
    print("Hello, World!")
```

### JavaScript Example

```javascript
function greet(name) {
    console.log(`Hello, ${name}!`);
}
```

## References

- [Official Documentation](https://example.com/docs)
- [API Reference](api.md)
- [Contributing Guide](CONTRIBUTING.md)

## License

MIT License

```

--------------------------------------------------------------------------------
/src/solidlsp/language_servers/elixir_tools/README.md:
--------------------------------------------------------------------------------

```markdown
# Elixir Language Server Integration

This directory contains the integration for Elixir language support using [Next LS](https://github.com/elixir-tools/next-ls) from the elixir-tools project.

> **⚠️ Windows Not Supported**: Next LS does not provide Windows binaries, so Elixir language server integration is only available on Linux and macOS.

## Known Issues

### Next LS v0.23.3 Timeout Enumeration Bug
There is a known intermittent bug in Next LS v0.23.3 where `textDocument/definition` requests can fail with:
```
Protocol.UndefinedError: protocol Enumerable not implemented for :timeout of type Atom
```

This bug is tracked in [Next LS Issue #543](https://github.com/elixir-tools/next-ls/issues/543) and primarily occurs in CI environments. The affected test (`test_request_defining_symbol_none`) is marked as expected to fail until this upstream bug is resolved.

## Prerequisites

Before using the Elixir language server integration, you need to have:

1. **Elixir** installed and available in your PATH
   - Install from: https://elixir-lang.org/install.html
   - Verify with: `elixir --version`

2. **Next LS** installed and available in your PATH
   - Install from: https://github.com/elixir-tools/next-ls#installation
   - Verify with: `nextls --version`

## Features

The Elixir integration provides:

- **Language Server Protocol (LSP) support** via Next LS
- **File extension recognition** for `.ex` and `.exs` files
- **Project structure awareness** with proper handling of Elixir-specific directories:
  - `_build/` - Compiled artifacts (ignored)
  - `deps/` - Dependencies (ignored)
  - `.elixir_ls/` - ElixirLS artifacts (ignored)
  - `cover/` - Coverage reports (ignored)
  - `lib/` - Source code (not ignored)
  - `test/` - Test files (not ignored)

## Configuration

The integration uses the default Next LS configuration with:

- **MIX_ENV**: `dev`
- **MIX_TARGET**: `host`
- **Experimental completions**: Disabled by default
- **Credo extension**: Enabled by default

## Usage

The Elixir language server is automatically selected when working with Elixir projects. It will be used for:

- Code completion
- Go to definition
- Find references
- Document symbols
- Hover information
- Code formatting
- Diagnostics (via Credo integration)

### Important: Project Compilation

Next LS requires your Elixir project to be **compiled** for optimal performance, especially for:
- Cross-file reference resolution
- Complete symbol information
- Accurate go-to-definition

**For production use**: Ensure your project is compiled with `mix compile` before using the language server.

**For testing**: The test suite automatically compiles the test repositories before running tests to ensure optimal Next LS performance.

## Testing

Run the Elixir-specific tests with:

```bash
pytest test/solidlsp/elixir/ -m elixir
```

## Implementation Details

- **Main class**: `ElixirTools` in `elixir_tools.py`
- **Initialization parameters**: Defined in `initialize_params.json`
- **Language identifier**: `"elixir"`
- **Command**: `nextls --stdio`

The implementation follows the same patterns as other language servers in this project, inheriting from `SolidLanguageServer` and providing Elixir-specific configuration and behavior. 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
<p align="center" style="text-align:center">
  <img src="resources/serena-logo.svg#gh-light-mode-only" style="width:500px">
  <img src="resources/serena-logo-dark-mode.svg#gh-dark-mode-only" style="width:500px">
</p>

* :rocket: Serena is a powerful **coding agent toolkit** capable of turning an LLM into a fully-featured agent that works **directly on your codebase**.
  Unlike most other tools, it is not tied to an LLM, framework or an interface, making it easy to use it in a variety of ways.
* :wrench: Serena provides essential **semantic code retrieval and editing tools** that are akin to an IDE's capabilities, extracting code entities at the symbol level and exploiting relational structure. When combined with an existing coding agent, these tools greatly enhance (token) efficiency.
* :free: Serena is **free & open-source**, enhancing the capabilities of LLMs you already have access to free of charge.

You can think of Serena as providing IDE-like tools to your LLM/coding agent. 
With it, the agent no longer needs to read entire files, perform grep-like searches or basic string replacements to find the right parts of the code and to edit code. 
Instead, it can use code-centric tools like `find_symbol`, `find_referencing_symbols` and `insert_after_symbol`.

<p align="center">
  <em>Serena is under active development! See the latest updates, upcoming features, and lessons learned to stay up to date.</em>
</p>

<p align="center">
  <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/Updates-1e293b?style=flat&logo=rss&logoColor=white&labelColor=1e293b" alt="Changelog" /></a>
  <a href="roadmap.md"><img src="https://img.shields.io/badge/Roadmap-14532d?style=flat&logo=target&logoColor=white&labelColor=14532d" alt="Roadmap" /></a>
  <a href="lessons_learned.md"><img src="https://img.shields.io/badge/Lessons-Learned-7c4700?style=flat&logo=readthedocs&logoColor=white&labelColor=7c4700" alt="Lessons Learned" /></a>
</p>

## LLM Integration

Serena provides the necessary [tools](https://oraios.github.io/serena/01-about/035_tools.html) for coding workflows, but an LLM is required to do the actual work,
orchestrating tool use.

In general, Serena can be integrated with an LLM in several ways:

* by using the **model context protocol (MCP)**.
  Serena provides an MCP server which integrates with
    * Claude Code and Claude Desktop,
    * terminal-based clients like Codex, Gemini-CLI, Qwen3-Coder, rovodev, OpenHands CLI and others,
    * IDEs like VSCode, Cursor or IntelliJ,
    * Extensions like Cline or Roo Code
    * Local clients like [OpenWebUI](https://docs.openwebui.com/openapi-servers/mcp), [Jan](https://jan.ai/docs/mcp-examples/browser/browserbase#enable-mcp), [Agno](https://docs.agno.com/introduction/playground) and others
* by using [mcpo to connect it to ChatGPT](docs/03-special-guides/serena_on_chatgpt.md) or other clients that don't support MCP but do support tool calling via OpenAPI.
* by incorporating Serena's tools into an agent framework of your choice, as illustrated [here](docs/03-special-guides/custom_agent.md).
  Serena's tool implementation is decoupled from the framework-specific code and can thus easily be adapted to any agent framework.

## Serena in Action

#### Demonstration 1: Efficient Operation in Claude Code

A demonstration of Serena efficiently retrieving and editing code within Claude Code, thereby saving tokens and time. Efficient operations are not only useful for saving costs, but also for generally improving the generated code's quality. This effect may be less pronounced in very small projects, but often becomes of crucial importance in larger ones.

https://github.com/user-attachments/assets/ab78ebe0-f77d-43cc-879a-cc399efefd87

#### Demonstration 2: Serena in Claude Desktop

A demonstration of Serena implementing a small feature for itself (a better log GUI) with Claude Desktop.
Note how Serena's tools enable Claude to find and edit the right symbols.

https://github.com/user-attachments/assets/6eaa9aa1-610d-4723-a2d6-bf1e487ba753

### Programming Language Support & Semantic Analysis Capabilities

Serena's semantic code analysis capabilities build on **language servers** using the widely implemented
language server protocol (LSP). The LSP provides a set of versatile code querying
and editing functionalities based on symbolic understanding of the code.
Equipped with these capabilities, Serena discovers and edits code just like a seasoned developer
making use of an IDE's capabilities would.
Serena can efficiently find the right context and do the right thing even in very large and
complex projects! So not only is it free and open-source, it frequently achieves better results
than existing solutions that charge a premium.

Language servers provide support for a wide range of programming languages.
With Serena's LSP library, we provide **support for over 30 programming languages**, including
AL, Bash, C#, C/C++, Clojure, Dart, Elixir, Elm, Erlang, Fortran, Go, Haskell, Java, Javascript, Julia, Kotlin, Lua, Markdown, Nix, Perl, PHP, Python, R, Ruby, Rust, Scala, Swift, TypeScript, YAML and Zig.

> [!IMPORTANT]
> Some languages require additional dependencies to be installed; see the [Language Support](https://oraios.github.io/serena/01-about/020_programming-languages.html) page for details.

## Quick Start

**Prerequisites**. Serena is managed by *uv*. If you don’t already have it, you need to [install uv](https://docs.astral.sh/uv/getting-started/installation/) before proceeding.

**Starting the MCP Server**. The easiest way to start the Serena MCP server is by running the latest version from GitHub using uvx.
Issue this command to see available options:

```bash
uvx --from git+https://github.com/oraios/serena serena start-mcp-server --help
```

**Configuring Your Client**. To connect Serena to your preferred MCP client, you typically need to [configure a launch command in your client](https://oraios.github.io/serena/02-usage/030_clients.html).
Follow the link for specific instructions on how to set up Serena for Claude Code, Codex, Claude Desktop, MCP-enabled IDEs and other clients (such as local and web-based GUIs). 

> [!TIP]
> While getting started quickly is easy, Serena is a powerful toolkit with many configuration options.
> We highly recommend reading through the [user guide](https://oraios.github.io/serena/02-usage/000_intro.html) to get the most out of Serena.
> 
> Specifically, we recommend to read about ...
>   * [Serena's project-based workflow](https://oraios.github.io/serena/02-usage/040_workflow.html) and
>   * [configuring Serena](https://oraios.github.io/serena/02-usage/050_configuration.html).

## User Guide

Please refer to the [user guide](https://oraios.github.io/serena/02-usage/000_intro.html) for detailed instructions on how to use Serena effectively.

## Community Feedback

Most users report that Serena has strong positive effects on the results of their coding agents, even when used within
very capable agents like Claude Code. Serena is often described to be a [game changer](https://www.reddit.com/r/ClaudeAI/comments/1lfsdll/try_out_serena_mcp_thank_me_later/), providing an enormous [productivity boost](https://www.reddit.com/r/ClaudeCode/comments/1mguoia/absolutely_insane_improvement_of_claude_code).

Serena excels at navigating and manipulating complex codebases, providing tools that support precise code retrieval and editing in the presence of large, strongly structured codebases.
However, when dealing with tasks that involve only very few/small files, you may not benefit from including Serena on top of your existing coding agent.
In particular, when writing code from scratch, Serena will not provide much value initially, as the more complex structures that Serena handles more gracefully than simplistic, file-based approaches are yet to be created.

Several videos and blog posts have talked about Serena:

* YouTube:
    * [AI Labs](https://www.youtube.com/watch?v=wYWyJNs1HVk&t=1s)
    * [Yo Van Eyck](https://www.youtube.com/watch?v=UqfxuQKuMo8&t=45s)
    * [JeredBlu](https://www.youtube.com/watch?v=fzPnM3ySmjE&t=32s)

* Blog posts:
    * [Serena's Design Principles](https://medium.com/@souradip1000/deconstructing-serenas-mcp-powered-semantic-code-understanding-architecture-75802515d116)
    * [Serena with Claude Code (in Japanese)](https://blog.lai.so/serena/)
    * [Turning Claude Code into a Development Powerhouse](https://robertmarshall.dev/blog/turning-claude-code-into-a-development-powerhouse/)

## Acknowledgements

### Sponsors

We are very grateful to our [sponsors](https://github.com/sponsors/oraios) who help us drive Serena's development. The core team
(the founders of [Oraios AI](https://oraios-ai.de/)) put in a lot of work in order to turn Serena into a useful open source project. 
So far, there is no business model behind this project, and sponsors are our only source of income from it.

Sponsors help us dedicating more time to the project, managing contributions, and working on larger features (like better tooling based on more advanced
LSP features, VSCode integration, debugging via the DAP, and several others).
If you find this project useful to your work, or would like to accelerate the development of Serena, consider becoming a sponsor.

We are proud to announce that the Visual Studio Code team, together with Microsoft’s Open Source Programs Office and GitHub Open Source
have decided to sponsor Serena with a one-time contribution!

<p align="center">
  <img src="resources/vscode_sponsor_logo.png" alt="Visual Studio Code sponsor logo" width="220">
</p>

### Community Contributions

A significant part of Serena, especially support for various languages, was contributed by the open source community.
We are very grateful for the many contributors who made this possible and who played an important role in making Serena
what it is today.

### Technologies
We built Serena on top of multiple existing open-source technologies, the most important ones being:

1. [multilspy](https://github.com/microsoft/multilspy).
   A library which wraps language server implementations and adapts them for interaction via Python.
   It provided the basis for our library Solid-LSP (`src/solidlsp`).
   Solid-LSP provides pure synchronous LSP calls and extends the original library with the symbolic logic
   that Serena required.
2. [Python MCP SDK](https://github.com/modelcontextprotocol/python-sdk)
3. All the language servers that we use through Solid-LSP.

Without these projects, Serena would not have been possible (or would have been significantly more difficult to build).

## Customizing and Extending Serena

It is straightforward to extend Serena's AI functionality with your own ideas.
Simply implement a new tool by subclassing
`serena.agent.Tool` and implement the `apply` method with a signature
that matches the tool's requirements.
Once implemented, `SerenaAgent` will automatically have access to the new tool.

It is also relatively straightforward to add [support for a new programming language](/.serena/memories/adding_new_language_support_guide.md).

We look forward to seeing what the community will come up with!
For details on contributing, see [contributing guidelines](/CONTRIBUTING.md).

```

--------------------------------------------------------------------------------
/test/resources/repos/markdown/test_repo/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
# Contributing Guidelines

Thank you for considering contributing to this project!

## Table of Contents

- [Code of Conduct](#code-of-conduct)
- [Getting Started](#getting-started)
- [Development Setup](#development-setup)
- [Submitting Changes](#submitting-changes)

## Code of Conduct

Please be respectful and considerate in all interactions.

## Getting Started

To contribute:

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Submit a pull request

## Development Setup

### Prerequisites

- Git
- Node.js (v16+)
- npm or yarn

### Installation Steps

```bash
git clone https://github.com/example/repo.git
cd repo
npm install
```

## Submitting Changes

### Pull Request Process

1. Update documentation
2. Add tests for new features
3. Ensure all tests pass
4. Update the [README](README.md)

### Commit Messages

Use clear and descriptive commit messages:

- feat: Add new feature
- fix: Bug fix
- docs: Documentation changes
- test: Add or update tests

## Testing

Run the test suite before submitting:

```bash
npm test
```

For more information, see:

- [User Guide](guide.md)
- [API Reference](api.md)

## Questions?

Contact the maintainers or open an issue.

```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
# Contributing to Serena

Serena is under active development. We are just discovering what it can do and where the limitations lie.

Feel free to share your learnings by opening new issues, feature requests and extensions.

## Developer Environment Setup

You can have a local setup via `uv` or a docker interpreter-based setup. 
The repository is also configured to seamlessly work within a GitHub Codespace. See the instructions
for the various setup scenarios below.

Independently of how the setup was done, the virtual environment can be 
created and activated via `uv` (see below), and the various tasks like formatting, testing, and documentation building
can be executed using `poe`. For example, `poe format` will format the code, including the 
notebooks. Just run `poe` to see the available commands.

### Python (uv) setup

You can install a virtual environment with the required as follows

1. Create a new virtual environment: `uv venv`
2. Activate the environment:
    * On Linux/Unix/macOS or Windows with Git Bash: `source .venv/bin/activate`
    * On Windows outside of Git Bash: `.venv\Scripts\activate.bat` (in cmd/ps) or `source .venv/Scripts/activate` (in git-bash) 
3. Install the required packages with all extras: `uv pip install --all-extras -r pyproject.toml -e .`

## Running Tools Locally

The Serena tools (and in fact all Serena code) can be executed without an LLM, and also without
any MCP specifics (though you can use the mcp inspector, if you want).

An example script for running tools is provided in [scripts/demo_run_tools.py](scripts/demo_run_tools.py).

## Adding a New Supported Language

See the corresponding [memory](.serena/memories/adding_new_language_support_guide.md).
```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Development Commands

**Essential Commands (use these exact commands):**
- `uv run poe format` - Format code (BLACK + RUFF) - ONLY allowed formatting command
- `uv run poe type-check` - Run mypy type checking - ONLY allowed type checking command  
- `uv run poe test` - Run tests with default markers (excludes java/rust by default)
- `uv run poe test -m "python or go"` - Run specific language tests
- `uv run poe lint` - Check code style without fixing

**Test Markers:**
Available pytest markers for selective testing:
- `python`, `go`, `java`, `rust`, `typescript`, `php`, `perl`, `csharp`, `elixir`, `terraform`, `clojure`, `swift`, `bash`, `ruby`, `ruby_solargraph`
- `snapshot` - for symbolic editing operation tests

**Project Management:**
- `uv run serena-mcp-server` - Start MCP server from project root
- `uv run index-project` - Index project for faster tool performance

**Always run format, type-check, and test before completing any task.**

## Architecture Overview

Serena is a dual-layer coding agent toolkit:

### Core Components

**1. SerenaAgent (`src/serena/agent.py`)**
- Central orchestrator managing projects, tools, and user interactions
- Coordinates language servers, memory persistence, and MCP server interface
- Manages tool registry and context/mode configurations

**2. SolidLanguageServer (`src/solidlsp/ls.py`)**  
- Unified wrapper around Language Server Protocol (LSP) implementations
- Provides language-agnostic interface for symbol operations
- Handles caching, error recovery, and multiple language server lifecycle

**3. Tool System (`src/serena/tools/`)**
- **file_tools.py** - File system operations, search, regex replacements
- **symbol_tools.py** - Language-aware symbol finding, navigation, editing
- **memory_tools.py** - Project knowledge persistence and retrieval
- **config_tools.py** - Project activation, mode switching
- **workflow_tools.py** - Onboarding and meta-operations

**4. Configuration System (`src/serena/config/`)**
- **Contexts** - Define tool sets for different environments (desktop-app, agent, ide-assistant)
- **Modes** - Operational patterns (planning, editing, interactive, one-shot)
- **Projects** - Per-project settings and language server configs

### Language Support Architecture

Each supported language has:
1. **Language Server Implementation** in `src/solidlsp/language_servers/`
2. **Runtime Dependencies** - Automatic language server downloads when needed
3. **Test Repository** in `test/resources/repos/<language>/`
4. **Test Suite** in `test/solidlsp/<language>/`

### Memory & Knowledge System

- **Markdown-based storage** in `.serena/memories/` directories
- **Project-specific knowledge** persistence across sessions
- **Contextual retrieval** based on relevance
- **Onboarding support** for new projects

## Development Patterns

### Adding New Languages
1. Create language server class in `src/solidlsp/language_servers/`
2. Add to Language enum in `src/solidlsp/ls_config.py` 
3. Update factory method in `src/solidlsp/ls.py`
4. Create test repository in `test/resources/repos/<language>/`
5. Write test suite in `test/solidlsp/<language>/`
6. Add pytest marker to `pyproject.toml`

### Adding New Tools
1. Inherit from `Tool` base class in `src/serena/tools/tools_base.py`
2. Implement required methods and parameter validation
3. Register in appropriate tool registry
4. Add to context/mode configurations

### Testing Strategy
- Language-specific tests use pytest markers
- Symbolic editing operations have snapshot tests
- Integration tests in `test_serena_agent.py`
- Test repositories provide realistic symbol structures

## Configuration Hierarchy

Configuration is loaded from (in order of precedence):
1. Command-line arguments to `serena-mcp-server`
2. Project-specific `.serena/project.yml`
3. User config `~/.serena/serena_config.yml`
4. Active modes and contexts

## Key Implementation Notes

- **Symbol-based editing** - Uses LSP for precise code manipulation
- **Caching strategy** - Reduces language server overhead
- **Error recovery** - Automatic language server restart on crashes
- **Multi-language support** - 16+ languages with LSP integration
- **MCP protocol** - Exposes tools to AI agents via Model Context Protocol
- **Async operation** - Non-blocking language server interactions

## Working with the Codebase

- Project uses Python 3.11 with `uv` for dependency management
- Strict typing with mypy, formatted with black + ruff
- Language servers run as separate processes with LSP communication
- Memory system enables persistent project knowledge
- Context/mode system allows workflow customization
```

--------------------------------------------------------------------------------
/src/interprompt/util/__init__.py:
--------------------------------------------------------------------------------

```python

```

--------------------------------------------------------------------------------
/src/serena/config/__init__.py:
--------------------------------------------------------------------------------

```python

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/__init__.py:
--------------------------------------------------------------------------------

```python

```

--------------------------------------------------------------------------------
/test/solidlsp/bash/__init__.py:
--------------------------------------------------------------------------------

```python

```

--------------------------------------------------------------------------------
/test/solidlsp/dart/__init__.py:
--------------------------------------------------------------------------------

```python

```

--------------------------------------------------------------------------------
/test/solidlsp/yaml_ls/__init__.py:
--------------------------------------------------------------------------------

```python

```

--------------------------------------------------------------------------------
/src/solidlsp/language_servers/elixir_tools/__init__.py:
--------------------------------------------------------------------------------

```python


```

--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------

```python


```

--------------------------------------------------------------------------------
/test/serena/__init__.py:
--------------------------------------------------------------------------------

```python


```

--------------------------------------------------------------------------------
/test/resources/repos/scala/project/build.properties:
--------------------------------------------------------------------------------

```
sbt.version=1.10.1

```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------

```yaml
blank_issues_enabled: false
```

--------------------------------------------------------------------------------
/test/solidlsp/r/__init__.py:
--------------------------------------------------------------------------------

```python
# Empty init file for R tests

```

--------------------------------------------------------------------------------
/test/solidlsp/fortran/__init__.py:
--------------------------------------------------------------------------------

```python
# Fortran language server tests

```

--------------------------------------------------------------------------------
/test/solidlsp/haskell/__init__.py:
--------------------------------------------------------------------------------

```python
# Haskell language server tests

```

--------------------------------------------------------------------------------
/test/serena/config/__init__.py:
--------------------------------------------------------------------------------

```python
# Empty init file for test package

```

--------------------------------------------------------------------------------
/test/resources/repos/php/test_repo/simple_var.php:
--------------------------------------------------------------------------------

```php
<?php
$localVar = "test";
echo $localVar;
?> 
```

--------------------------------------------------------------------------------
/src/solidlsp/__init__.py:
--------------------------------------------------------------------------------

```python
# ruff: noqa
from .ls import SolidLanguageServer

```

--------------------------------------------------------------------------------
/test/resources/repos/kotlin/test_repo/src/main/kotlin/test_repo/Model.kt:
--------------------------------------------------------------------------------

```kotlin
package test_repo

data class Model(val name: String)
```

--------------------------------------------------------------------------------
/test/solidlsp/markdown/__init__.py:
--------------------------------------------------------------------------------

```python
"""Tests for markdown language server functionality."""

```

--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------

```yaml
# These are supported funding model platforms

github: oraios

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/custom_test/__init__.py:
--------------------------------------------------------------------------------

```python
"""
Custom test package for testing code parsing capabilities.
"""

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/examples/__init__.py:
--------------------------------------------------------------------------------

```python
"""
Examples package for demonstrating test_repo module usage.
"""

```

--------------------------------------------------------------------------------
/test/resources/repos/haskell/test_repo/stack.yaml:
--------------------------------------------------------------------------------

```yaml
resolver: ghc-9.8.4
system-ghc: true
install-ghc: false
packages:
  - .

```

--------------------------------------------------------------------------------
/test/resources/repos/nix/test_repo/scripts/hello.sh:
--------------------------------------------------------------------------------

```bash
#!/usr/bin/env bash
# Simple hello script for testing
echo "Hello from Nix!"
```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/scripts/__init__.py:
--------------------------------------------------------------------------------

```python
"""
Scripts package containing entry point scripts for the application.
"""

```

--------------------------------------------------------------------------------
/test/resources/repos/rust/test_repo/Cargo.toml:
--------------------------------------------------------------------------------

```toml
[package]
name = "rsandbox"
version = "0.1.0"
edition = "2021"

[dependencies]

```

--------------------------------------------------------------------------------
/test/resources/repos/rust/test_repo_2024/Cargo.toml:
--------------------------------------------------------------------------------

```toml
[package]
name = "rsandbox_2024"
version = "0.1.0"
edition = "2024"

[dependencies]
```

--------------------------------------------------------------------------------
/test/resources/repos/php/test_repo/helper.php:
--------------------------------------------------------------------------------

```php
<?php

function helperFunction(): void {
    echo "Helper function was called.";
}

?> 
```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/lib.rb:
--------------------------------------------------------------------------------

```ruby
class Calculator
  def add(a, b)
    a + b
  end

  def subtract(a, b)
    a - b
  end
end

```

--------------------------------------------------------------------------------
/docker_build_and_run.sh:
--------------------------------------------------------------------------------

```bash
#!/usr/bin/bash

docker build -t serena .

docker run -it --rm -v "$(pwd)":/workspace serena

```

--------------------------------------------------------------------------------
/scripts/mcp_server.py:
--------------------------------------------------------------------------------

```python
from serena.cli import start_mcp_server

if __name__ == "__main__":
    start_mcp_server()

```

--------------------------------------------------------------------------------
/test/resources/repos/kotlin/test_repo/src/main/kotlin/test_repo/Utils.kt:
--------------------------------------------------------------------------------

```kotlin
package test_repo

object Utils {
    fun printHello() {
        println("Hello from Utils!")
    }
}
```

--------------------------------------------------------------------------------
/scripts/print_tool_overview.py:
--------------------------------------------------------------------------------

```python
from serena.agent import ToolRegistry

if __name__ == "__main__":
    ToolRegistry().print_tool_overview()

```

--------------------------------------------------------------------------------
/test/resources/repos/typescript/test_repo/use_helper.ts:
--------------------------------------------------------------------------------

```typescript
import {helperFunction} from "./index";


export function useHelper() {
    helperFunction();
}

useHelper();

```

--------------------------------------------------------------------------------
/src/interprompt/__init__.py:
--------------------------------------------------------------------------------

```python
from .prompt_factory import autogenerate_prompt_factory_module

__all__ = ["autogenerate_prompt_factory_module"]

```

--------------------------------------------------------------------------------
/docs/03-special-guides/000_intro.md:
--------------------------------------------------------------------------------

```markdown
# Special Guides

This section contains special guides for certain topics that require more in-depth explanations.
```

--------------------------------------------------------------------------------
/test/resources/repos/rust/test_repo/src/lib.rs:
--------------------------------------------------------------------------------

```rust
// This function returns the sum of 2 + 2
pub fn add() -> i32 {
    let res = 2 + 2;
    res
}
pub fn multiply() -> i32 {
    2 * 3
}


```

--------------------------------------------------------------------------------
/test/resources/repos/java/test_repo/src/main/java/test_repo/Utils.java:
--------------------------------------------------------------------------------

```java
package test_repo;

public class Utils {
    public static void printHello() {
        System.out.println("Hello from Utils!");
    }
}

```

--------------------------------------------------------------------------------
/test/resources/repos/kotlin/test_repo/build.gradle.kts:
--------------------------------------------------------------------------------

```kotlin
plugins {
    kotlin("jvm") version "1.9.21"
    application
}

group = "test.serena"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}
```

--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------

```markdown
<meta http-equiv="refresh" content="0; url=01-about/000_intro.html">
If you are not redirected automatically, [click here](01-about/000_intro.html).

```

--------------------------------------------------------------------------------
/test/resources/repos/typescript/test_repo/.serena/project.yml:
--------------------------------------------------------------------------------

```yaml
excluded_tools: []
ignore_all_files_in_gitignore: true
ignored_paths: []
initial_prompt: ''
language: typescript
project_name: test_repo
read_only: false

```

--------------------------------------------------------------------------------
/test/resources/repos/kotlin/test_repo/src/main/kotlin/test_repo/ModelUser.kt:
--------------------------------------------------------------------------------

```kotlin
package test_repo

object ModelUser {
    @JvmStatic
    fun main(args: Array<String>) {
        val model = Model("Cascade")
        println(model.name)
    }
}
```

--------------------------------------------------------------------------------
/test/resources/repos/rust/test_repo/src/main.rs:
--------------------------------------------------------------------------------

```rust
use rsandbox::add;

fn main() {
    println!("Hello, World!");
    println!("Good morning!");
    println!("add result: {}", add());
    println!("inserted line");
}

```

--------------------------------------------------------------------------------
/test/resources/repos/java/test_repo/src/main/java/test_repo/ModelUser.java:
--------------------------------------------------------------------------------

```java
package test_repo;

public class ModelUser {
    public static void main(String[] args) {
        Model model = new Model("Cascade");
        System.out.println(model.getName());
    }
}

```

--------------------------------------------------------------------------------
/test/resources/repos/dart/test_repo/pubspec.yaml:
--------------------------------------------------------------------------------

```yaml
name: test_repo
description: A test repository for Serena Dart language server testing
version: 1.0.0

environment:
  sdk: '>=3.0.0 <4.0.0'

dependencies:
  
dev_dependencies:
  lints: ^3.0.0
```

--------------------------------------------------------------------------------
/test/resources/repos/java/test_repo/src/main/java/test_repo/Model.java:
--------------------------------------------------------------------------------

```java
package test_repo;

public class Model {
    private String name;

    public Model(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
{
    "cSpell.words": [
        "agno",
        "asyncio",
        "genai",
        "getpid",
        "Gopls",
        "langsrv",
        "multilspy",
        "pixi",
        "sensai",
        "vibing"
    ],
}

```

--------------------------------------------------------------------------------
/sync.py:
--------------------------------------------------------------------------------

```python
import os
from repo_dir_sync import LibRepo, OtherRepo

r = LibRepo(name="serena", libDirectory="src")
r.add(OtherRepo(name="mux", branch="mux", pathToLib=os.path.join("..", "serena-multiplexer", "src-serena")))
r.runMain()

```

--------------------------------------------------------------------------------
/test/resources/repos/go/test_repo/main.go:
--------------------------------------------------------------------------------

```go
package main

import "fmt"

func main() {
    fmt.Println("Hello, Go!")
    Helper()
}

func Helper() {
    fmt.Println("Helper function called")
}

type DemoStruct struct {
    Field int
}

func UsingHelper() {
    Helper()
}

```

--------------------------------------------------------------------------------
/test/resources/repos/typescript/test_repo/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2017",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  },
  "include": ["**/*.ts"]
}

```

--------------------------------------------------------------------------------
/src/serena/tools/__init__.py:
--------------------------------------------------------------------------------

```python
# ruff: noqa
from .tools_base import *
from .file_tools import *
from .symbol_tools import *
from .memory_tools import *
from .cmd_tools import *
from .config_tools import *
from .workflow_tools import *
from .jetbrains_tools import *

```

--------------------------------------------------------------------------------
/test/resources/repos/php/test_repo/index.php:
--------------------------------------------------------------------------------

```php
<?php

require_once 'helper.php';

function greet(string $name): string {
    return "Hello, " . $name . "!";
}

$userName = "PHP User";
$greeting = greet($userName);

echo $greeting;

helperFunction();

function useHelperFunction() {
    helperFunction();
}

?> 
```

--------------------------------------------------------------------------------
/test/resources/repos/typescript/test_repo/index.ts:
--------------------------------------------------------------------------------

```typescript
export class DemoClass {
    value: number;
    constructor(value: number) {
        this.value = value;
    }
    printValue() {
        console.log(this.value);
    }
}

export function helperFunction() {
    const demo = new DemoClass(42);
    demo.printValue();
}

helperFunction();

```

--------------------------------------------------------------------------------
/src/interprompt/util/class_decorators.py:
--------------------------------------------------------------------------------

```python
from typing import Any


def singleton(cls: type[Any]) -> Any:
    instance = None

    def get_instance(*args: Any, **kwargs: Any) -> Any:
        nonlocal instance
        if instance is None:
            instance = cls(*args, **kwargs)
        return instance

    return get_instance

```

--------------------------------------------------------------------------------
/test/resources/repos/rust/test_repo_2024/src/main.rs:
--------------------------------------------------------------------------------

```rust
fn main() {
    println!("Hello, Rust 2024 edition!");
    let result = add(2, 3);
    println!("2 + 3 = {}", result);
}

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add() {
        assert_eq!(add(2, 3), 5);
    }
}
```

--------------------------------------------------------------------------------
/test/resources/repos/kotlin/test_repo/src/main/kotlin/test_repo/Main.kt:
--------------------------------------------------------------------------------

```kotlin
package test_repo

object Main {
    @JvmStatic
    fun main(args: Array<String>) {
        Utils.printHello()
        val model = Model("Cascade")
        println(model.name)
        acceptModel(model)
    }

    fun acceptModel(m: Model?) {
        // Do nothing, just for LSP reference
    }
}
```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/main.rb:
--------------------------------------------------------------------------------

```ruby
require './lib.rb'

class DemoClass
  attr_accessor :value

  def initialize(value)
    @value = value
  end

  def print_value
    puts @value
  end
end

def helper_function(number = 42)
  demo = DemoClass.new(number)
  Calculator.new.add(demo.value, 10)
  demo.print_value
end

helper_function

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/nested.py:
--------------------------------------------------------------------------------

```python
class OuterClass:
    class NestedClass:
        def find_me(self):
            pass

    def nested_test(self):
        class WithinMethod:
            pass

        def func_within_func():
            pass

        a = self.NestedClass()  # noqa: F841


b = OuterClass().NestedClass().find_me()

```

--------------------------------------------------------------------------------
/docs/02-usage/000_intro.md:
--------------------------------------------------------------------------------

```markdown
# Usage

Serena can be used in various ways and supports coding workflows through a project-based approach.
Its configuration is flexible and allows tailoring it to your specific needs.

In this section, you will find general usage instructions as well as concrete instructions for selected integrations.

```

--------------------------------------------------------------------------------
/test/resources/repos/swift/test_repo/Package.swift:
--------------------------------------------------------------------------------

```swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "test_repo",
    products: [
        .library(
            name: "test_repo",
            targets: ["test_repo"]),
    ],
    targets: [
        .target(
            name: "test_repo",
            dependencies: []),
    ]
)
```

--------------------------------------------------------------------------------
/docs/create_toc.py:
--------------------------------------------------------------------------------

```python
import os
from pathlib import Path

# This script provides a platform-independent way of making the jupyter-book call (used in pyproject.toml)
folder = Path(__file__).parent
toc_file = folder / "_toc.yml"
cmd = f"jupyter-book toc from-project docs -e .rst -e .md -e .ipynb >{toc_file}"
print(cmd)
os.system(cmd)

```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/agent.yml:
--------------------------------------------------------------------------------

```yaml
description: All tools except InitialInstructionsTool for agent context
prompt: |
  You are running in agent context where the system prompt is provided externally. You should use symbolic
  tools when possible for code understanding and modification.
excluded_tools:
  - initial_instructions

tool_description_overrides: {}
```

--------------------------------------------------------------------------------
/test/resources/repos/rust/test_repo_2024/src/lib.rs:
--------------------------------------------------------------------------------

```rust
pub fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

pub struct Calculator {
    pub result: i32,
}

impl Calculator {
    pub fn new() -> Self {
        Calculator { result: 0 }
    }

    pub fn add(&mut self, value: i32) {
        self.result += value;
    }

    pub fn get_result(&self) -> i32 {
        self.result
    }
}
```

--------------------------------------------------------------------------------
/test/resources/repos/java/test_repo/src/main/java/test_repo/Main.java:
--------------------------------------------------------------------------------

```java
package test_repo;

public class Main {
    public static void main(String[] args) {
        Utils.printHello();
        Model model = new Model("Cascade");
        System.out.println(model.getName());
        acceptModel(model);
    }
    public static void acceptModel(Model m) {
        // Do nothing, just for LSP reference
    }
}

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/complex_types.py:
--------------------------------------------------------------------------------

```python
from typing import TypedDict

a: list[int] = [1]


class CustomListInt(list[int]):
    def some_method(self):
        pass


class CustomTypedDict(TypedDict):
    a: int
    b: str


class Outer2:
    class InnerTypedDict(TypedDict):
        a: int
        b: str


class ComplexExtension(Outer2.InnerTypedDict, total=False):
    c: bool

```

--------------------------------------------------------------------------------
/test/resources/repos/yaml/test_repo/config.yaml:
--------------------------------------------------------------------------------

```yaml
# Application configuration
app:
  name: test-application
  version: 1.0.0
  port: 8080
  debug: true

database:
  host: localhost
  port: 5432
  name: testdb
  username: admin
  password: secret123

logging:
  level: info
  format: json
  outputs:
    - console
    - file

features:
  authentication: true
  caching: false
  monitoring: true

```

--------------------------------------------------------------------------------
/src/serena/resources/config/modes/mode.template.yml:
--------------------------------------------------------------------------------

```yaml
# See Serena's documentation for more details on concept of modes.
description: Description of the mode, not used in the code.
prompt: Prompt that will form part of the message sent to the model when activating this mode.
excluded_tools: []

# several tools are excluded by default and have to be explicitly included by the user
included_optional_tools: []
```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/oaicompat-agent.yml:
--------------------------------------------------------------------------------

```yaml
description: All tools except InitialInstructionsTool for agent context, uses OpenAI compatible tool definitions
prompt: |
  You are running in agent context where the system prompt is provided externally. You should use symbolic
  tools when possible for code understanding and modification.
excluded_tools:
  - initial_instructions

tool_description_overrides: {}
```

--------------------------------------------------------------------------------
/test/resources/repos/zig/test_repo/zls.json:
--------------------------------------------------------------------------------

```json
{
    "enable_build_on_save": true,
    "build_on_save_args": ["build"],
    "enable_autofix": false,
    "semantic_tokens": "full",
    "enable_inlay_hints": true,
    "inlay_hints_show_builtin": true,
    "inlay_hints_exclude_single_argument": true,
    "inlay_hints_show_parameter_name": true,
    "skip_std_references": false,
    "max_detail_length": 1048576
}

```

--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------

```json
{
  "name": "serena Project",
  "dockerFile": "../Dockerfile",
  "workspaceFolder": "/workspaces/serena",
  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash",
    "python.pythonPath": "/usr/local/bin/python",
  },
  "extensions": [
    "ms-python.python",
    "ms-toolsai.jupyter",
    "ms-python.vscode-pylance"
  ],
  "forwardPorts": [],
  "remoteUser": "root",
}

```

--------------------------------------------------------------------------------
/test/solidlsp/clojure/__init__.py:
--------------------------------------------------------------------------------

```python
from pathlib import Path

from solidlsp.language_servers.clojure_lsp import verify_clojure_cli


def _test_clojure_cli() -> bool:
    try:
        verify_clojure_cli()
        return False
    except (FileNotFoundError, RuntimeError):
        return True


CLI_FAIL = _test_clojure_cli()
TEST_APP_PATH = Path("src") / "test_app"
CORE_PATH = str(TEST_APP_PATH / "core.clj")
UTILS_PATH = str(TEST_APP_PATH / "utils.clj")

```

--------------------------------------------------------------------------------
/test/resources/repos/haskell/test_repo/package.yaml:
--------------------------------------------------------------------------------

```yaml
name: haskell-test-repo
version: 0.1.0.0
github: "test/haskell-test-repo"
license: BSD3
author: "Test Author"
maintainer: "[email protected]"

dependencies:
  - base >= 4.7 && < 5

library:
  source-dirs: src
  exposed-modules:
    - Calculator
    - Helper

executables:
  haskell-test-repo-exe:
    main: Main.hs
    source-dirs: app
    dependencies:
      - haskell-test-repo

default-extensions:
  - OverloadedStrings

```

--------------------------------------------------------------------------------
/src/serena/util/class_decorators.py:
--------------------------------------------------------------------------------

```python
from typing import Any


# duplicate of interprompt.class_decorators
# We don't want to depend on interprompt for this in serena, so we duplicate it here
def singleton(cls: type[Any]) -> Any:
    instance = None

    def get_instance(*args: Any, **kwargs: Any) -> Any:
        nonlocal instance
        if instance is None:
            instance = cls(*args, **kwargs)
        return instance

    return get_instance

```

--------------------------------------------------------------------------------
/src/serena/util/cli_util.py:
--------------------------------------------------------------------------------

```python
def ask_yes_no(question: str, default: bool | None = None) -> bool:
    default_prompt = "Y/n" if default else "y/N"

    while True:
        answer = input(f"{question} [{default_prompt}] ").strip().lower()
        if answer == "" and default is not None:
            return default
        if answer in ("y", "yes"):
            return True
        if answer in ("n", "no"):
            return False
        print("Please answer yes/y or no/n.")

```

--------------------------------------------------------------------------------
/test/serena/test_edit_marker.py:
--------------------------------------------------------------------------------

```python
from serena.tools import CreateTextFileTool, ReadFileTool, Tool


class TestEditMarker:
    def test_tool_can_edit_method(self):
        """Test that Tool.can_edit() method works correctly"""
        # Non-editing tool should return False
        assert issubclass(ReadFileTool, Tool)
        assert not ReadFileTool.can_edit()

        # Editing tool should return True
        assert issubclass(CreateTextFileTool, Tool)
        assert CreateTextFileTool.can_edit()

```

--------------------------------------------------------------------------------
/.github/workflows/junie.yml:
--------------------------------------------------------------------------------

```yaml
name: Junie
run-name: Junie run ${{ inputs.run_id }}

permissions:
  contents: write

on:
  workflow_dispatch:
    inputs:
      run_id:
        description: "id of workflow process"
        required: true
      workflow_params:
        description: "stringified params"
        required: true

jobs:
  call-workflow-passing-data:
    uses: jetbrains-junie/junie-workflows/.github/workflows/ej-issue.yml@main
    with:
      workflow_params: ${{ inputs.workflow_params }}

```

--------------------------------------------------------------------------------
/src/serena/resources/config/modes/no-onboarding.yml:
--------------------------------------------------------------------------------

```yaml
description: Onboarding was already performed, exclude all onboarding tools
prompt: |
  You have already performed onboarding, meaning that memories have already been created.
  Read a list of available memories using the `list_memories` tool before proceeding with the task.
  You don't need to read the actual memories, just remember that they exist and that you can read them later if they are relevant for your task.
excluded_tools:
  - onboarding
  - check_onboarding_performed

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/name_collisions.py:
--------------------------------------------------------------------------------

```python
# ruff: noqa
var_will_be_overwritten = 1

var_will_be_overwritten = 2


def func_using_overwritten_var():
    print(var_will_be_overwritten)


class ClassWillBeOverwritten:
    def method1(self):
        pass


class ClassWillBeOverwritten:
    def method2(self):
        pass


def func_will_be_overwritten():
    pass


def func_will_be_overwritten():
    pass


def func_calling_overwritten_func():
    func_will_be_overwritten()


def func_calling_overwritten_class():
    ClassWillBeOverwritten()

```

--------------------------------------------------------------------------------
/docs/02-usage/010_prerequisites.md:
--------------------------------------------------------------------------------

```markdown
# Prerequisites

## Package Manager: uv

Serena is managed by `uv`.
If you do not have it yet, install it following the instructions [here](https://docs.astral.sh/uv/getting-started/installation/).

## Language-Specific Requirements

Depending on the programming language you intend to use with Serena, you may need to install additional tools or SDKs if you 
intend to use the language server backend of Serena.  
See the [language support documentation](../01-about/020_programming-languages) for details. 

```

--------------------------------------------------------------------------------
/test/resources/repos/elm/test_repo/elm.json:
--------------------------------------------------------------------------------

```json
{
    "type": "application",
    "source-directories": [
        "."
    ],
    "elm-version": "0.19.1",
    "dependencies": {
        "direct": {
            "elm/browser": "1.0.2",
            "elm/core": "1.0.5",
            "elm/html": "1.0.0"
        },
        "indirect": {
            "elm/json": "1.1.3",
            "elm/time": "1.0.0",
            "elm/url": "1.0.0",
            "elm/virtual-dom": "1.0.3"
        }
    },
    "test-dependencies": {
        "direct": {},
        "indirect": {}
    }
}

```

--------------------------------------------------------------------------------
/src/serena/prompt_factory.py:
--------------------------------------------------------------------------------

```python
import os

from serena.constants import PROMPT_TEMPLATES_DIR_IN_USER_HOME, PROMPT_TEMPLATES_DIR_INTERNAL
from serena.generated.generated_prompt_factory import PromptFactory


class SerenaPromptFactory(PromptFactory):
    """
    A class for retrieving and rendering prompt templates and prompt lists.
    """

    def __init__(self) -> None:
        os.makedirs(PROMPT_TEMPLATES_DIR_IN_USER_HOME, exist_ok=True)
        super().__init__(prompts_dir=[PROMPT_TEMPLATES_DIR_IN_USER_HOME, PROMPT_TEMPLATES_DIR_INTERNAL])

```

--------------------------------------------------------------------------------
/src/serena/__init__.py:
--------------------------------------------------------------------------------

```python
__version__ = "0.1.4"

import logging

log = logging.getLogger(__name__)


def serena_version() -> str:
    """
    :return: the version of the package, including git status if available.
    """
    from serena.util.git import get_git_status

    version = __version__
    try:
        git_status = get_git_status()
        if git_status is not None:
            version += f"-{git_status.commit[:8]}"
            if not git_status.is_clean:
                version += "-dirty"
    except:
        pass
    return version

```

--------------------------------------------------------------------------------
/.github/workflows/codespell.yml:
--------------------------------------------------------------------------------

```yaml
# Codespell configuration is within pyproject.toml
---
name: Codespell

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read

jobs:
  codespell:
    name: Check for spelling errors
    runs-on: ubuntu-latest
    timeout-minutes: 2

    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Annotate locations with typos
        uses: codespell-project/codespell-problem-matcher@v1
      - name: Codespell
        uses: codespell-project/actions-codespell@v2

```

--------------------------------------------------------------------------------
/src/solidlsp/util/subprocess_util.py:
--------------------------------------------------------------------------------

```python
import platform
import subprocess


def subprocess_kwargs() -> dict:
    """
    Returns a dictionary of keyword arguments for subprocess calls, adding platform-specific
    flags that we want to use consistently.
    """
    kwargs = {}
    if platform.system() == "Windows":
        kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW  # type: ignore
    return kwargs


def quote_arg(arg: str) -> str:
    """
    Adds quotes around an argument if it contains spaces.
    """
    if " " not in arg:
        return arg
    return f'"{arg}"'

```

--------------------------------------------------------------------------------
/src/serena/resources/config/modes/planning.yml:
--------------------------------------------------------------------------------

```yaml
description: Only read-only tools, focused on analysis and planning
prompt: |
  You are operating in planning mode. Your task is to analyze code but not write any code.
  The user may ask you to assist in creating a comprehensive plan, or to learn something about the codebase -
  either a small aspect of it or about the whole project.
excluded_tools:
  - create_text_file
  - replace_symbol_body
  - insert_after_symbol
  - insert_before_symbol
  - delete_lines
  - replace_lines
  - insert_at_line
  - execute_shell_command
  - replace_content

```

--------------------------------------------------------------------------------
/scripts/print_mode_context_options.py:
--------------------------------------------------------------------------------

```python
from serena.config.context_mode import SerenaAgentContext, SerenaAgentMode

if __name__ == "__main__":
    print("---------- Available modes: ----------")
    for mode_name in SerenaAgentMode.list_registered_mode_names():
        mode = SerenaAgentMode.load(mode_name)
        mode.print_overview()
        print("\n")
    print("---------- Available contexts: ----------")
    for context_name in SerenaAgentContext.list_registered_context_names():
        context = SerenaAgentContext.load(context_name)
        context.print_overview()
        print("\n")

```

--------------------------------------------------------------------------------
/test/resources/repos/erlang/test_repo/rebar.config:
--------------------------------------------------------------------------------

```
%% Rebar3 configuration for test repository
{erl_opts, [
    debug_info,
    warnings_as_errors,
    warn_export_all,
    warn_unused_import,
    {i, "include"}
]}.

{deps, [
    {eunit, ".*", {git, "https://github.com/richcarl/eunit.git", {tag, "2.3.6"}}}
]}.

{profiles, [
    {test, [
        {erl_opts, [debug_info]},
        {deps, [
            {proper, "1.3.0"}
        ]}
    ]}
]}.

{cover_enabled, true}.
{cover_print_enabled, true}.

{dialyzer, [
    {warnings, [
        unmatched_returns,
        error_handling,
        race_conditions,
        underspecs
    ]}
]}.
```

--------------------------------------------------------------------------------
/test/resources/repos/swift/test_repo/src/utils.swift:
--------------------------------------------------------------------------------

```swift
import Foundation

public struct Utils {
    public static func formatDate(_ date: Date) -> String {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        return formatter.string(from: date)
    }
    
    public static func calculateArea(radius: Double) -> Double {
        return Double.pi * radius * radius
    }
}

public extension String {
    func isValidEmail() -> Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
        return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: self)
    }
}
```

--------------------------------------------------------------------------------
/scripts/gen_prompt_factory.py:
--------------------------------------------------------------------------------

```python
"""
Autogenerates the `prompt_factory.py` module
"""

from pathlib import Path

from sensai.util import logging

from interprompt import autogenerate_prompt_factory_module
from serena.constants import PROMPT_TEMPLATES_DIR_INTERNAL, REPO_ROOT

log = logging.getLogger(__name__)


def main():
    autogenerate_prompt_factory_module(
        prompts_dir=PROMPT_TEMPLATES_DIR_INTERNAL,
        target_module_path=str(Path(REPO_ROOT) / "src" / "serena" / "generated" / "generated_prompt_factory.py"),
    )


if __name__ == "__main__":
    logging.run_main(main)

```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------

```markdown
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.

```

--------------------------------------------------------------------------------
/src/serena/resources/config/internal_modes/jetbrains.yml:
--------------------------------------------------------------------------------

```yaml
description: JetBrains tools replace language server-based tools
prompt: |
  You have access to the very powerful JetBrains tools for symbolic operations:
    * `jet_brains_find_symbol` replaces `find_symbol`
    * `jet_brains_find_referencing_symbols` replaces `find_referencing_symbols`
    * `jet_brains_get_symbols_overview` replaces `get_symbols_overview`
excluded_tools:
  - find_symbol
  - find_referencing_symbols
  - get_symbols_overview
  - restart_language_server
included_optional_tools:
  - jet_brains_find_symbol
  - jet_brains_find_referencing_symbols
  - jet_brains_get_symbols_overview

```

--------------------------------------------------------------------------------
/test/resources/repos/yaml/test_repo/data.yaml:
--------------------------------------------------------------------------------

```yaml
# Sample data structure
users:
  - id: 1
    name: John Doe
    email: [email protected]
    roles:
      - admin
      - developer
    active: true

  - id: 2
    name: Jane Smith
    email: [email protected]
    roles:
      - developer
    active: true

  - id: 3
    name: Bob Johnson
    email: [email protected]
    roles:
      - viewer
    active: false

projects:
  - name: project-alpha
    status: active
    team:
      - John Doe
      - Jane Smith
    tags:
      - backend
      - api

  - name: project-beta
    status: planning
    team:
      - Jane Smith
    tags:
      - frontend
      - ui

```

--------------------------------------------------------------------------------
/src/serena/resources/config/modes/interactive.yml:
--------------------------------------------------------------------------------

```yaml
description: Interactive mode for clarification and step-by-step work
prompt: |
  You are operating in interactive mode. You should engage with the user throughout the task, asking for clarification
  whenever anything is unclear, insufficiently specified, or ambiguous.
  
  Break down complex tasks into smaller steps and explain your thinking at each stage. When you're uncertain about
  a decision, present options to the user and ask for guidance rather than making assumptions.
  
  Focus on providing informative results for intermediate steps so the user can follow along with your progress and
  provide feedback as needed.
excluded_tools: []
```

--------------------------------------------------------------------------------
/src/serena/resources/config/modes/onboarding.yml:
--------------------------------------------------------------------------------

```yaml
description: Only read-only tools, focused on analysis and planning
prompt: |
  You are operating in onboarding mode. This is the first time you are seeing the project.
  Your task is to collect relevant information about it and to save memories using the tools provided.
  Call relevant onboarding tools for more instructions on how to do this.
  In this mode, you should not be modifying any existing files.
  If you are also in interactive mode and something about the project is unclear, ask the user for clarification.
excluded_tools:
  - create_text_file
  - replace_symbol_body
  - insert_after_symbol
  - insert_before_symbol
  - delete_lines
  - replace_lines
  - insert_at_line
  - execute_shell_command

```

--------------------------------------------------------------------------------
/src/serena/util/git.py:
--------------------------------------------------------------------------------

```python
import logging

from sensai.util.git import GitStatus

from .shell import subprocess_check_output

log = logging.getLogger(__name__)


def get_git_status() -> GitStatus | None:
    try:
        commit_hash = subprocess_check_output(["git", "rev-parse", "HEAD"])
        unstaged = bool(subprocess_check_output(["git", "diff", "--name-only"]))
        staged = bool(subprocess_check_output(["git", "diff", "--staged", "--name-only"]))
        untracked = bool(subprocess_check_output(["git", "ls-files", "--others", "--exclude-standard"]))
        return GitStatus(
            commit=commit_hash, has_unstaged_changes=unstaged, has_staged_uncommitted_changes=staged, has_untracked_files=untracked
        )
    except:
        return None

```

--------------------------------------------------------------------------------
/test/resources/repos/csharp/test_repo/Models/Person.cs:
--------------------------------------------------------------------------------

```csharp
using TestProject;

namespace TestProject.Models
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
        
        public Person(string name, int age, string email)
        {
            Name = name;
            Age = age;
            Email = email;
        }
        
        public override string ToString()
        {
            return $"{Name} ({Age}) - {Email}";
        }
        
        public bool IsAdult()
        {
            return Age >= 18;
        }
        
        public int CalculateYearsUntilRetirement()
        {
            var calculator = new Calculator();
            return calculator.Subtract(65, Age);
        }
    }
}
```

--------------------------------------------------------------------------------
/test/resources/repos/al/test_repo/app.json:
--------------------------------------------------------------------------------

```json
{
  "id": "00000001-0000-0000-0000-000000000001",
  "name": "Test AL Project",
  "publisher": "Serena Test Publisher",
  "version": "1.0.0.0",
  "brief": "Test project for AL Language Server in Serena",
  "description": "This project contains AL code samples for testing language server features",
  "privacyStatement": "",
  "EULA": "",
  "help": "",
  "url": "https://github.com/oraios/serena",
  "logo": "",
  "dependencies": [],
  "screenshots": [],
  "platform": "1.0.0.0",
  "application": "26.0.0.0",
  "idRanges": [
    {
      "from": 50000,
      "to": 50100
    }
  ],
  "resourceExposurePolicy": {
    "allowDebugging": true,
    "allowDownloadingSource": true,
    "includeSourceInSymbolFile": true
  },
  "runtime": "15.0",
  "features": ["NoImplicitWith"],
  "target": "Cloud"
}
```

--------------------------------------------------------------------------------
/src/solidlsp/util/cache.py:
--------------------------------------------------------------------------------

```python
import logging
from typing import Any, Optional

from sensai.util.pickle import dump_pickle, load_pickle

log = logging.getLogger(__name__)


def load_cache(path: str, version: Any) -> Optional[Any]:
    data = load_pickle(path)
    if not isinstance(data, dict) or "__cache_version" not in data:
        log.info("Cache is outdated (expected version %s). Ignoring cache at %s", version, path)
        return None
    saved_version = data["__cache_version"]
    if saved_version != version:
        log.info("Cache is outdated (expected version %s, got %s). Ignoring cache at %s", version, saved_version, path)
        return None
    return data["obj"]


def save_cache(path: str, version: Any, obj: Any) -> None:
    data = {"__cache_version": version, "obj": obj}
    dump_pickle(data, path)

```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/nested.rb:
--------------------------------------------------------------------------------

```ruby
class OuterClass
  def initialize
    @value = "outer"
  end

  def outer_method
    inner_function = lambda do |x|
      x * 2
    end
    
    result = inner_function.call(5)
    puts "Result: #{result}"
  end

  class NestedClass
    def initialize(name)
      @name = name
    end

    def find_me
      "Found in NestedClass: #{@name}"
    end

    def nested_method
      puts "Nested method called"
    end

    class DeeplyNested
      def deep_method
        "Deep inside"
      end
    end
  end

  module NestedModule
    def module_method
      "Module method"
    end

    class ModuleClass
      def module_class_method
        "Module class method"
      end
    end
  end
end

# Test usage of nested classes
outer = OuterClass.new
nested = OuterClass::NestedClass.new("test")
result = nested.find_me
```

--------------------------------------------------------------------------------
/test/resources/repos/yaml/test_repo/services.yml:
--------------------------------------------------------------------------------

```yaml
# Docker compose services definition
version: '3.8'

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./html:/usr/share/nginx/html
    environment:
      - NGINX_HOST=localhost
      - NGINX_PORT=80
    networks:
      - frontend

  api:
    image: node:18
    ports:
      - "3000:3000"
    depends_on:
      - database
    environment:
      - NODE_ENV=production
      - DB_HOST=database
    networks:
      - frontend
      - backend

  database:
    image: postgres:15
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=mydb
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=password
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes:
  db-data:

```

--------------------------------------------------------------------------------
/test/resources/repos/csharp/test_repo/Program.cs:
--------------------------------------------------------------------------------

```csharp
using System;

namespace TestProject
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
            
            var calculator = new Calculator();
            int result = calculator.Add(5, 3);
            Console.WriteLine($"5 + 3 = {result}");
        }
    }
    
    public class Calculator
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
        
        public int Subtract(int a, int b)
        {
            return a - b;
        }
        
        public int Multiply(int a, int b)
        {
            return a * b;
        }
        
        public double Divide(int a, int b)
        {
            if (b == 0)
            {
                throw new DivideByZeroException("Cannot divide by zero");
            }
            return (double)a / b;
        }
    }
}
```

--------------------------------------------------------------------------------
/docs/02-usage/070_security.md:
--------------------------------------------------------------------------------

```markdown
# Security Considerations

As fundamental abilities for a coding agent, Serena contains tools for executing shell commands and modifying files.
Therefore, if the respective tool calls are not monitored or restricted (and execution takes place in a sensitive environment), 
there is a risk of unintended consequences.

Therefore, to reduce the risk of unintended consequences when using Serena, it is recommended to
  * back up your work regularly (e.g. use a version control system like Git),
  * monitor tool executions carefully (e.g. via your MCP client, provided that it supports it),
  * consider enabling read-only mode for your project (set `read_only: True` in project.yml) if you only want to analyze code without modifying it,
  * restrict the set of allowed tools via the [configuration](050_configuration),
  * use a sandboxed environment for running Serena (e.g. by [using Docker](docker)).

```

--------------------------------------------------------------------------------
/src/serena/resources/config/modes/one-shot.yml:
--------------------------------------------------------------------------------

```yaml
description: Focus on completely finishing a task without interaction
prompt: |
  You are operating in one-shot mode. Your goal is to complete the entire task autonomously without further user interaction.
  You should assume auto-approval for all tools and continue working until the task is completely finished.
  
  If the task is planning, your final result should be a comprehensive plan. If the task is coding, your final result
  should be working code with all requirements fulfilled. Try to understand what the user asks you to do
  and to assume as little as possible.

  Only abort the task if absolutely necessary, such as when critical information is missing that cannot be inferred
  from the codebase.

  It may be that you have not received a task yet. In this case, wait for the user to provide a task, this will be the 
  only time you should wait for user interaction.
excluded_tools: []

```

--------------------------------------------------------------------------------
/test/solidlsp/elixir/__init__.py:
--------------------------------------------------------------------------------

```python
import platform


def _test_nextls_available() -> str:
    """Test if Next LS is available and return error reason if not."""
    # Check if we're on Windows (Next LS doesn't support Windows)
    if platform.system() == "Windows":
        return "Next LS does not support Windows"

    # Try to import and check Elixir availability
    try:
        from solidlsp.language_servers.elixir_tools.elixir_tools import ElixirTools

        # Check if Elixir is installed
        elixir_version = ElixirTools._get_elixir_version()
        if not elixir_version:
            return "Elixir is not installed or not in PATH"

        return ""  # No error, Next LS should be available

    except ImportError as e:
        return f"Failed to import ElixirTools: {e}"
    except Exception as e:
        return f"Error checking Next LS availability: {e}"


NEXTLS_UNAVAILABLE_REASON = _test_nextls_available()
NEXTLS_UNAVAILABLE = bool(NEXTLS_UNAVAILABLE_REASON)

```

--------------------------------------------------------------------------------
/scripts/agno_agent.py:
--------------------------------------------------------------------------------

```python
from agno.models.anthropic.claude import Claude
from agno.models.google.gemini import Gemini
from agno.os import AgentOS
from sensai.util import logging
from sensai.util.helper import mark_used

from serena.agno import SerenaAgnoAgentProvider

mark_used(Gemini, Claude)

# initialize logging
if __name__ == "__main__":
    logging.configure(level=logging.INFO)

# Define the model to use (see Agno documentation for supported models; these are just examples)
# model = Claude(id="claude-3-7-sonnet-20250219")
model = Gemini(id="gemini-2.5-pro")

# Create the Serena agent using the existing provider
serena_agent = SerenaAgnoAgentProvider.get_agent(model)

# Create AgentOS app with the Serena agent
agent_os = AgentOS(
    description="Serena coding assistant powered by AgentOS",
    id="serena-agentos",
    agents=[serena_agent],
)

app = agent_os.get_app()

if __name__ == "__main__":
    # Start the AgentOS server
    agent_os.serve(app="agno_agent:app", reload=False)

```

--------------------------------------------------------------------------------
/scripts/demo_run_tools.py:
--------------------------------------------------------------------------------

```python
"""
This script demonstrates how to use Serena's tools locally, useful
for testing or development. Here the tools will be operation the serena repo itself.
"""

import json
from pprint import pprint

from serena.agent import SerenaAgent
from serena.constants import REPO_ROOT
from serena.tools import FindFileTool, FindReferencingSymbolsTool, GetSymbolsOverviewTool, JetBrainsFindSymbolTool, SearchForPatternTool

if __name__ == "__main__":
    agent = SerenaAgent(project=REPO_ROOT)

    # apply a tool
    find_symbol_tool = agent.get_tool(JetBrainsFindSymbolTool)
    find_refs_tool = agent.get_tool(FindReferencingSymbolsTool)
    find_file_tool = agent.get_tool(FindFileTool)
    search_pattern_tool = agent.get_tool(SearchForPatternTool)
    overview_tool = agent.get_tool(GetSymbolsOverviewTool)

    result = agent.execute_task(
        lambda: find_symbol_tool.apply("displayBasicStats"),
    )
    pprint(json.loads(result))
    # input("Press Enter to continue...")

```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/services.rb:
--------------------------------------------------------------------------------

```ruby
require './lib.rb'
require './models.rb'

module Services
  class UserService
    attr_reader :users

    def initialize
      @users = {}
    end

    def create_user(id, name)
      user = User.new(id, name)
      @users[id] = user
      user
    end

    def get_user(id)
      @users[id]
    end

    def delete_user(id)
      @users.delete(id)
    end

    private

    def validate_user_data(id, name)
      return false if id.nil? || name.nil?
      return false if name.empty?
      true
    end
  end

  class ItemService
    def initialize
      @items = []
    end

    def add_item(item)
      @items << item
    end

    def find_item(id)
      @items.find { |item| item.id == id }
    end
  end
end

# Module-level function
def create_service_container
  {
    user_service: Services::UserService.new,
    item_service: Services::ItemService.new
  }
end

# Variables for testing
user_service_instance = Services::UserService.new
item_service_instance = Services::ItemService.new
```

--------------------------------------------------------------------------------
/test/resources/repos/swift/test_repo/src/main.swift:
--------------------------------------------------------------------------------

```swift
import Foundation

// Main entry point
func main() {
    let calculator = Calculator()
    let result = calculator.add(5, 3)
    print("Result: \(result)")
    
    let user = User(name: "Alice", age: 30)
    user.greet()
    
    let area = Utils.calculateArea(radius: 5.0)
    print("Circle area: \(area)")
}

class Calculator {
    func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
    
    func multiply(_ a: Int, _ b: Int) -> Int {
        return a * b
    }
}

struct User {
    let name: String
    let age: Int
    
    func greet() {
        print("Hello, my name is \(name) and I am \(age) years old.")
    }
    
    func isAdult() -> Bool {
        return age >= 18
    }
}

enum Status {
    case active
    case inactive
    case pending
}

protocol Drawable {
    func draw()
}

class Circle: Drawable {
    let radius: Double
    
    init(radius: Double) {
        self.radius = radius
    }
    
    func draw() {
        print("Drawing a circle with radius \(radius)")
    }
}

// Call main
main()
```

--------------------------------------------------------------------------------
/docs/01-about/000_intro.md:
--------------------------------------------------------------------------------

```markdown
# About Serena

* Serena is a powerful **coding agent toolkit** capable of turning an LLM into a fully-featured agent that works
  **directly on your codebase**.
  Unlike most other tools, it is not tied to an LLM, framework or an interface, making it easy to use it in a variety of ways.
* Serena provides essential **semantic code retrieval and editing tools** that are akin to an IDE's capabilities,
  extracting code entities at the symbol level and exploiting relational structure.
  When combined with an existing coding agent, these tools greatly enhance (token) efficiency.
* Serena is **free & open-source**, enhancing the capabilities of LLMs you already have access to free of charge.

Therefore, you can think of Serena as providing IDE-like tools to your LLM/coding agent.
With it, the agent no longer needs to read entire files, perform grep-like searches or string replacements to find and
edit the right code.
Instead, it can use code-centred tools like `find_symbol`, `find_referencing_symbols` and `insert_after_symbol`.

```

--------------------------------------------------------------------------------
/docs/02-usage/060_dashboard.md:
--------------------------------------------------------------------------------

```markdown
# The Dashboard and GUI Tool

Serena comes with built-in tools for monitoring and managing the current session:

* the **web-based dashboard** (enabled by default)
  
  The dashboard provides detailed information on your Serena session, the current configuration and provides access to logs.
  Some settings (e.g. the current set of active programming languages) can also be directly modified through the dashboard.

  The dashboard is supported on all platforms.
  
  By default, it will be accessible at `http://localhost:24282/dashboard/index.html`,
  but a higher port may be used if the default port is unavailable/multiple instances are running.

* the **GUI tool** (disabled by default)
  
  The GUI tool is a native application window which displays logs.

  This is mainly supported on Windows, but it may also work on Linux; macOS is unsupported.

Both can be configured in Serena's [configuration](050_configuration) file (`serena_config.yml`).
If enabled, they will automatically be opened as soon as the Serena agent/MCP server is started.

```

--------------------------------------------------------------------------------
/test/resources/repos/markdown/test_repo/guide.md:
--------------------------------------------------------------------------------

```markdown
# User Guide

This guide provides detailed instructions for using the test repository.

## Getting Started

Welcome to the user guide. This document covers:

- Basic concepts
- Advanced features
- Troubleshooting

### Basic Concepts

The fundamental concepts you need to understand:

#### Headers and Structure

Markdown documents use headers to create structure. Headers are created using `#` symbols.

#### Links and References

Internal links can reference other documents:

- [Back to README](README.md)
- [See API documentation](api.md)

### Advanced Features

For advanced users, we provide:

1. Custom extensions
2. Plugin support
3. Theme customization

## Configuration

Configuration options are stored in `config.yaml`:

```yaml
server:
  port: 8080
  host: localhost
```

## Troubleshooting

If you encounter issues:

1. Check the [README](README.md) first
2. Review [common issues](CONTRIBUTING.md)
3. Contact support

## Next Steps

After reading this guide, check out:

- [API Reference](api.md)
- [Contributing Guidelines](CONTRIBUTING.md)

```

--------------------------------------------------------------------------------
/docs/01-about/030_serena-in-action.md:
--------------------------------------------------------------------------------

```markdown
# Serena in Action

## Demonstration 1: Efficient Operation in Claude Code

A demonstration of Serena efficiently retrieving and editing code within Claude Code, thereby saving tokens and time. Efficient operations are not only useful for saving costs, but also for generally improving the generated code's quality. This effect may be less pronounced in very small projects, but often becomes of crucial importance in larger ones.

<video src="https://github.com/user-attachments/assets/ab78ebe0-f77d-43cc-879a-cc399efefd87"
controls
preload="metadata"
style="max-width: 100%; height: auto;">
Your browser does not support the video tag.
</video>

## Demonstration 2: Serena in Claude Desktop

A demonstration of Serena implementing a small feature for itself (a better log GUI) with Claude Desktop.
Note how Serena's tools enable Claude to find and edit the right symbols.

<video src="https://github.com/user-attachments/assets/6eaa9aa1-610d-4723-a2d6-bf1e487ba753"
controls
preload="metadata"
style="max-width: 100%; height: auto;">
Your browser does not support the video tag.
</video>

```

--------------------------------------------------------------------------------
/test/resources/repos/java/test_repo/pom.xml:
--------------------------------------------------------------------------------

```
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>test_repo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>Java Test Repo</name>
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    </properties>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

```

--------------------------------------------------------------------------------
/test/resources/repos/markdown/test_repo/api.md:
--------------------------------------------------------------------------------

```markdown
# API Reference

Complete API documentation for the test repository.

## Classes

### Client

The main client class for interacting with the API.

#### Methods

##### `connect()`

Establishes a connection to the server.

**Parameters:**
- `host`: Server hostname
- `port`: Server port number

**Returns:** Connection object

##### `disconnect()`

Closes the connection to the server.

**Returns:** None

### Server

Server-side implementation.

#### Configuration

```json
{
  "host": "localhost",
  "port": 8080,
  "timeout": 30
}
```

## Functions

### `initialize(config)`

Initializes the system with the provided configuration.

**Parameters:**
- `config`: Configuration dictionary

**Example:**

```python
config = {
    "host": "localhost",
    "port": 8080
}
initialize(config)
```

### `shutdown()`

Gracefully shuts down the system.

## Error Handling

Common errors and their solutions:

- `ConnectionError`: Check network connectivity
- `TimeoutError`: Increase timeout value
- `ConfigError`: Validate configuration file

## See Also

- [User Guide](guide.md)
- [README](README.md)
- [Contributing](CONTRIBUTING.md)

```

--------------------------------------------------------------------------------
/src/serena/util/general.py:
--------------------------------------------------------------------------------

```python
import os
from typing import Literal, overload

from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap

from serena.constants import SERENA_FILE_ENCODING


def _create_YAML(preserve_comments: bool = False) -> YAML:
    """
    Creates a YAML that can load/save with comments if preserve_comments is True.
    """
    typ = None if preserve_comments else "safe"
    result = YAML(typ=typ)
    result.preserve_quotes = preserve_comments
    return result


@overload
def load_yaml(path: str, preserve_comments: Literal[False]) -> dict: ...
@overload
def load_yaml(path: str, preserve_comments: Literal[True]) -> CommentedMap: ...
def load_yaml(path: str, preserve_comments: bool = False) -> dict | CommentedMap:
    with open(path, encoding=SERENA_FILE_ENCODING) as f:
        yaml = _create_YAML(preserve_comments)
        return yaml.load(f)


def save_yaml(path: str, data: dict | CommentedMap, preserve_comments: bool = False) -> None:
    yaml = _create_YAML(preserve_comments)
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "w", encoding=SERENA_FILE_ENCODING) as f:
        yaml.dump(data, f)

```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/context.template.yml:
--------------------------------------------------------------------------------

```yaml
# See Serena's documentation for more details on concept of contexts.
description: Description of the context, not used in the code.
prompt: Prompt that will form part of the system prompt/initial instructions for agents started in this context.
excluded_tools: []

# several tools are excluded by default and have to be explicitly included by the user
included_optional_tools: []

# mapping of tool names to an override of their descriptions (the default description is the docstring of the Tool's apply method).
# Sometimes, tool descriptions are too long (e.g., for ChatGPT), or users may want to override them for another reason.
tool_description_overrides: {}

# whether to assume that Serena shall only work on a single project in this context (provided that a project is given
# when Serena is started).
# If set to true and a project is provided at startup, the set of tools is limited to those required by the project's
# concrete configuration, and other tools are excluded completely, allowing the set of tools to be minimal.
# The `activate_project` tool will, therefore, be disabled in this case, as project switching is not allowed.
single_project: false
```

--------------------------------------------------------------------------------
/docs/01-about/010_llm-integration.md:
--------------------------------------------------------------------------------

```markdown
# LLM Integration

Serena provides the necessary [tools](035_tools) for coding workflows, but an LLM is required to do the actual work,
orchestrating tool use.

In general, Serena can be integrated with an LLM in several ways:

* by using the **model context protocol (MCP)**.
  Serena provides an MCP server which integrates with
    * Claude Code and Claude Desktop,
    * Terminal-based clients like Codex, Gemini-CLI, Qwen3-Coder, rovodev, OpenHands CLI and others,
    * IDEs like VSCode, Cursor or IntelliJ,
    * Extensions like Cline or Roo Code
    * Local clients like [OpenWebUI](https://docs.openwebui.com/openapi-servers/mcp), [Jan](https://jan.ai/docs/mcp-examples/browser/browserbase#enable-mcp), [Agno](https://docs.agno.com/introduction/playground) and others
* by using [mcpo to connect it to ChatGPT](../03-special-guides/serena_on_chatgpt.md) or other clients that don't support MCP but do support tool calling via OpenAPI.
* by incorporating Serena's tools into an agent framework of your choice, as illustrated [here](../03-special-guides/custom_agent).
  Serena's tool implementation is decoupled from the framework-specific code and can thus easily be adapted to any agent framework.

```

--------------------------------------------------------------------------------
/compose.yaml:
--------------------------------------------------------------------------------

```yaml
services:
  serena:
    image: serena:latest
    # To work with projects, you must mount them as volumes:
    # volumes:
      # - ./my-project:/workspace/my-project
      # - /path/to/another/project:/workspace/another-project
    build:
      context: ./
      dockerfile: Dockerfile
      target: production
    ports:
      - "${SERENA_PORT:-9121}:9121"  # MCP server port
      - "${SERENA_DASHBOARD_PORT:-24282}:24282"  # Dashboard port (default 0x5EDA = 24282)
    environment:
      - SERENA_DOCKER=1
    command:
      - "uv run --directory . serena-mcp-server --transport sse --port 9121 --host 0.0.0.0"
      # Add the context for the IDE assistant
      # - "uv run --directory . serena-mcp-server --transport sse --port 9121 --host 0.0.0.0 --context ide-assistant"

  serena-dev:
    image: serena:dev
    build:
      context: ./
      dockerfile: Dockerfile
      target: development
    tty: true
    stdin_open: true
    environment:
      - SERENA_DOCKER=1
    volumes:
      - .:/workspaces/serena
    ports:
      - "${SERENA_PORT:-9121}:9121"  # MCP server port
      - "${SERENA_DASHBOARD_PORT:-24282}:24282"  # Dashboard port
    command:
      - "uv run --directory . serena-mcp-server"

```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/desktop-app.yml:
--------------------------------------------------------------------------------

```yaml
description: All tools included for desktop app context
prompt: |
  You are running in desktop app context where the tools give you access to the code base as well as some
  access to the file system, if configured. You interact with the user through a chat interface that is separated
  from the code base. As a consequence, if you are in interactive mode, your communication with the user should
  involve high-level thinking and planning as well as some summarization of any code edits that you make.
  For viewing the code edits the user will view them in a separate code editor window, and the back-and-forth
  between the chat and the code editor should be minimized as well as facilitated by you.
  If complex changes have been made, advise the user on how to review them in the code editor.
  If complex relationships that the user asked for should be visualized or explained, consider creating
  a diagram in addition to your text-based communication. Note that in the chat interface you have various rendering
  options for text, html, and mermaid diagrams, as has been explained to you in your initial instructions.
excluded_tools: []
included_optional_tools:
  - switch_modes

tool_description_overrides: {}

```

--------------------------------------------------------------------------------
/.github/workflows/docs.yaml:
--------------------------------------------------------------------------------

```yaml
name: Docs Build

on:
  push:
    branches: [ main ]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.11

      - name: Install uv
        run: pip install uv

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ~/.cache/uv
          key: uv-${{ hashFiles('pyproject.toml') }}

      - name: Install dependencies
        run: |
          uv venv
          uv pip install -e ".[dev]"

      - name: Build docs
        run: uv run poe doc-build
        continue-on-error: false

      - name: Upload Pages artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs/_build

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

```

--------------------------------------------------------------------------------
/test/solidlsp/erlang/__init__.py:
--------------------------------------------------------------------------------

```python
import platform


def _test_erlang_ls_available() -> str:
    """Test if Erlang LS is available and return error reason if not."""
    # Check if we're on Windows (Erlang LS doesn't support Windows)
    if platform.system() == "Windows":
        return "Erlang LS does not support Windows"

    # Try to import and check Erlang availability
    try:
        from solidlsp.language_servers.erlang_language_server import ErlangLanguageServer

        # Check if Erlang/OTP is installed
        erlang_version = ErlangLanguageServer._get_erlang_version()
        if not erlang_version:
            return "Erlang/OTP is not installed or not in PATH"

        # Check if rebar3 is available (commonly used build tool)
        rebar3_available = ErlangLanguageServer._check_rebar3_available()
        if not rebar3_available:
            return "rebar3 is not installed or not in PATH (required for project compilation)"

        return ""  # No error, Erlang LS should be available

    except ImportError as e:
        return f"Failed to import ErlangLanguageServer: {e}"
    except Exception as e:
        return f"Error checking Erlang LS availability: {e}"


ERLANG_LS_UNAVAILABLE_REASON = _test_erlang_ls_available()
ERLANG_LS_UNAVAILABLE = bool(ERLANG_LS_UNAVAILABLE_REASON)

```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/issue--bug--performance-problem--question-.md:
--------------------------------------------------------------------------------

```markdown
---
name: Issue (bug, performance problem, question)
about: General Issue
title: ''
labels: ''
assignees: ''

---

I have:

- [ ] Read the readme and verified that the issue cannot be solved by adjusting configuration
- [ ] Understood that Serena's dashboard can be disabled through the config
- [ ] Understood that by default a client session will start a separate instance of a Serena server. 
- [ ] Understood that for multi-agent setups, the SSE mode should be used.
- [ ] Verified that non-project files are ignored using either gitignore or the corresponding setting in `.serena/project.yml`
- [ ] Have looked for similar issues and discussions, including closed ones
- [ ] Made sure it's an actual issue and not a question - those should be opened as discussion instead.

If you have encountered a real and new issue:

- [ ] I performed `<uv invocation> serena project health-check`
- [ ] I indexed the project as described in the readme
- [ ] Added sufficient explanation of my setup: the MCP client, the OS, the programming language, any config adjustments or relevant project specifics
- [ ] Explained how the issue arose, added instructions on how to reproduce it (if possible)
- [ ] If the issue happens on an open source project, I have added the link
- [ ] Wrote a meaningful title and description

```

--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------

```yaml
name: Publish Python Package

on:
  release:
    types: [created]

  workflow_dispatch:
    inputs:
      tag:
        description: 'Tag name for the release (e.g., v0.1.0)'
        required: true
        default: 'v0.1.0'

env:
  # Set this to true manually in the GitHub workflow UI if you want to publish to PyPI
  # Will always publish to testpypi
  PUBLISH_TO_PYPI: true

jobs:
  publish:
    name: Publish the serena-agent package
    runs-on: ubuntu-latest

    permissions:
      id-token: write  # Required for trusted publishing
      contents: write  # Required for updating artifact

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install the latest version of uv
        uses: astral-sh/setup-uv@v6
        with:
          version: "latest"

      - name: Build package
        run: uv build

      - name: Upload artifacts to GitHub Release
        if: env.PUBLISH_TO_PYPI == 'true'
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ github.event.inputs.tag || github.ref_name }}
          files: |
            dist/*.tar.gz
            dist/*.whl

      - name: Publish to TestPyPI
        run: uv publish --index testpypi

      - name: Publish to PyPI (conditional)
        if: env.PUBLISH_TO_PYPI == 'true'
        run: uv publish

```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/models.rb:
--------------------------------------------------------------------------------

```ruby
class User
  attr_accessor :id, :name, :email

  def initialize(id, name, email = nil)
    @id = id
    @name = name
    @email = email
  end

  def full_info
    info = "User: #{@name} (ID: #{@id})"
    info += ", Email: #{@email}" if @email
    info
  end

  def to_hash
    {
      id: @id,
      name: @name,
      email: @email
    }
  end

  def self.from_hash(hash)
    new(hash[:id], hash[:name], hash[:email])
  end

  class << self
    def default_user
      new(0, "Guest")
    end
  end
end

class Item
  attr_reader :id, :name, :price

  def initialize(id, name, price)
    @id = id
    @name = name
    @price = price
  end

  def discounted_price(discount_percent)
    @price * (1 - discount_percent / 100.0)
  end

  def description
    "#{@name}: $#{@price}"
  end
end

module ItemHelpers
  def format_price(price)
    "$#{sprintf('%.2f', price)}"
  end

  def calculate_tax(price, tax_rate = 0.08)
    price * tax_rate
  end
end

class Order
  include ItemHelpers

  def initialize
    @items = []
    @total = 0
  end

  def add_item(item, quantity = 1)
    @items << { item: item, quantity: quantity }
    calculate_total
  end

  def total_with_tax
    tax = calculate_tax(@total)
    @total + tax
  end

  private

  def calculate_total
    @total = @items.sum { |entry| entry[:item].price * entry[:quantity] }
  end
end
```

--------------------------------------------------------------------------------
/.serena/memories/suggested_commands.md:
--------------------------------------------------------------------------------

```markdown
# Suggested Commands

## Development Tasks (using uv and poe)

The following tasks should generally be executed using `uv run poe <task_name>`.

- `format`: This is the **only** allowed command for formatting. Run as `uv run poe format`.
- `type-check`: This is the **only** allowed command for type checking. Run as `uv run poe type-check`.
- `test`: This is the preferred command for running tests (`uv run poe test [args]`). You can select subsets of tests with markers,
   the current markers are
   ```toml
    markers = [
        "python: language server running for Python",
        "go: language server running for Go",
        "java: language server running for Java",
        "rust: language server running for Rust",
        "typescript: language server running for TypeScript",
        "php: language server running for PHP",
        "snapshot: snapshot tests for symbolic editing operations",
    ]
   ```
  By default, `uv run poe test` uses the markers set in the env var `PYTEST_MARKERS`, or, if it unset, uses `-m "not java and not rust and not isolated process"`.
  You can override this behavior by simply passing the `-m` option to `uv run poe test`, e.g. `uv run poe test -m "python or go"`.

For finishing a task, make sure format, type-check and test pass! Run them at the end of the task
and if needed fix any issues that come up and run them again until they pass.
```

--------------------------------------------------------------------------------
/src/serena/generated/generated_prompt_factory.py:
--------------------------------------------------------------------------------

```python
# ruff: noqa
# black: skip
# mypy: ignore-errors

# NOTE: This module is auto-generated from interprompt.autogenerate_prompt_factory_module, do not edit manually!

from interprompt.multilang_prompt import PromptList
from interprompt.prompt_factory import PromptFactoryBase
from typing import Any


class PromptFactory(PromptFactoryBase):
    """
    A class for retrieving and rendering prompt templates and prompt lists.
    """

    def create_onboarding_prompt(self, *, system: Any) -> str:
        return self._render_prompt("onboarding_prompt", locals())

    def create_think_about_collected_information(self) -> str:
        return self._render_prompt("think_about_collected_information", locals())

    def create_think_about_task_adherence(self) -> str:
        return self._render_prompt("think_about_task_adherence", locals())

    def create_think_about_whether_you_are_done(self) -> str:
        return self._render_prompt("think_about_whether_you_are_done", locals())

    def create_summarize_changes(self) -> str:
        return self._render_prompt("summarize_changes", locals())

    def create_prepare_for_new_conversation(self) -> str:
        return self._render_prompt("prepare_for_new_conversation", locals())

    def create_system_prompt(
        self, *, available_markers: Any, available_tools: Any, context_system_prompt: Any, mode_system_prompts: Any
    ) -> str:
        return self._render_prompt("system_prompt", locals())

```

--------------------------------------------------------------------------------
/test/resources/repos/bash/test_repo/main.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash

# Main script demonstrating various bash features

# Global variables
readonly SCRIPT_NAME="Main Script"
COUNTER=0
declare -a ITEMS=("item1" "item2" "item3")

# Function definitions
function greet_user() {
    local username="$1"
    local greeting_type="${2:-default}"
    
    case "$greeting_type" in
        "formal")
            echo "Good day, ${username}!"
            ;;
        "casual")
            echo "Hey ${username}!"
            ;;
        *)
            echo "Hello, ${username}!"
            ;;
    esac
}

function process_items() {
    local -n items_ref=$1
    local operation="$2"
    
    for item in "${items_ref[@]}"; do
        case "$operation" in
            "count")
                ((COUNTER++))
                echo "Processing item $COUNTER: $item"
                ;;
            "uppercase")
                echo "${item^^}"
                ;;
            *)
                echo "Unknown operation: $operation"
                return 1
                ;;
        esac
    done
}

# Main execution
main() {
    echo "Starting $SCRIPT_NAME"
    
    if [[ $# -eq 0 ]]; then
        echo "Usage: $0 <username> [greeting_type]"
        exit 1
    fi
    
    local user="$1"
    local greeting="${2:-default}"
    
    greet_user "$user" "$greeting"
    
    echo "Processing items..."
    process_items ITEMS "count"
    
    echo "Script completed successfully"
}

# Run main function with all arguments
main "$@"

```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/codex.yml:
--------------------------------------------------------------------------------

```yaml
description: Non-symbolic editing tools and general shell tool are excluded
prompt: |
  You are running in IDE assistant context where file operations, basic (line-based) edits and reads, 
  and shell commands are handled by your own, internal tools.
  The initial instructions and the current config inform you on which tools are available to you,
  and how to use them.
  Don't attempt to use any excluded tools, instead rely on your own internal tools
  for achieving the basic file or shell operations.
  
  If serena's tools can be used for achieving your task, 
  you should prioritize them. In particular, it is important that you avoid reading entire source code files,
  unless it is strictly necessary! Instead, for exploring and reading code in a token-efficient manner, 
  you should use serena's overview and symbolic search tools. The call of the read_file tool on an entire source code 
  file should only happen in exceptional cases, usually you should first explore the file (by itself or as part of exploring
  the directory containing it) using the symbol_overview tool, and then make targeted reads using find_symbol and other symbolic tools.
  For non-code files or for reads where you don't know the symbol's name path you can use the patterns searching tool,
  using the read_file as a last resort.

excluded_tools:
  - create_text_file
  - read_file
  - execute_shell_command
  - prepare_for_new_conversation
  - replace_content


tool_description_overrides: {}


```

--------------------------------------------------------------------------------
/src/interprompt/jinja_template.py:
--------------------------------------------------------------------------------

```python
from typing import Any

import jinja2
import jinja2.meta
import jinja2.nodes
import jinja2.visitor

from interprompt.util.class_decorators import singleton


class ParameterizedTemplateInterface:
    def get_parameters(self) -> list[str]: ...


@singleton
class _JinjaEnvProvider:
    def __init__(self) -> None:
        self._env: jinja2.Environment | None = None

    def get_env(self) -> jinja2.Environment:
        if self._env is None:
            self._env = jinja2.Environment()
        return self._env


class JinjaTemplate(ParameterizedTemplateInterface):
    def __init__(self, template_string: str) -> None:
        self._template_string = template_string
        self._template = _JinjaEnvProvider().get_env().from_string(self._template_string)
        parsed_content = self._template.environment.parse(self._template_string)
        self._parameters = sorted(jinja2.meta.find_undeclared_variables(parsed_content))

    def render(self, **params: Any) -> str:
        """Renders the template with the given kwargs. You can find out which parameters are required by calling get_parameter_names()."""
        return self._template.render(**params)

    def get_parameters(self) -> list[str]:
        """A sorted list of parameter names that are extracted from the template string. It is impossible to know the types of the parameter
        values, they can be primitives, dicts or dict-like objects.

        :return: the list of parameter names
        """
        return self._parameters

```

--------------------------------------------------------------------------------
/test/serena/test_tool_parameter_types.py:
--------------------------------------------------------------------------------

```python
import logging

import pytest

from serena.config.serena_config import SerenaConfig
from serena.mcp import SerenaMCPFactorySingleProcess
from serena.tools.tools_base import ToolRegistry


@pytest.mark.parametrize("context", ("chatgpt", "codex", "oaicompat-agent"))
def test_all_tool_parameters_have_type(context):
    """
    For every tool exposed by Serena, ensure that the generated
    Open‑AI schema contains a ``type`` entry for each parameter.
    """
    cfg = SerenaConfig(gui_log_window_enabled=False, web_dashboard=False, log_level=logging.ERROR)
    registry = ToolRegistry()
    cfg.included_optional_tools = tuple(registry.get_tool_names_optional())
    factory = SerenaMCPFactorySingleProcess(context=context)
    # Initialize the agent so that the tools are available
    factory._instantiate_agent(cfg, [])
    tools = list(factory._iter_tools())

    for tool in tools:
        mcp_tool = factory.make_mcp_tool(tool, openai_tool_compatible=True)
        params = mcp_tool.parameters

        # Collect any parameter that lacks a type
        issues = []
        print(f"Checking tool {tool}")

        if "properties" not in params:
            issues.append(f"Tool {tool.get_name()!r} missing properties section")
        else:
            for pname, prop in params["properties"].items():
                if "type" not in prop:
                    issues.append(f"Tool {tool.get_name()!r} parameter {pname!r} missing 'type'")
        if issues:
            raise AssertionError("\n".join(issues))

```

--------------------------------------------------------------------------------
/llms-install.md:
--------------------------------------------------------------------------------

```markdown
# MCP Installation instructions

This document is mainly used as instructions for AI-assistants like Cline and others that
try to do an automatic install based on freeform instructions.

0. Make sure `uv` is installed. If not, install it using either `curl -LsSf https://astral.sh/uv/install.sh | sh` (macOS, Linux) or
   `powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"` (Windows). Find the path to the `uv` executable,
   you'll need it later.
1. Clone the repo with `git clone [email protected]:oraios/serena.git` and change into its dir (e.g., `cd serena`)
2. Check if `serena_config.yml` exists. If not, create it  with `cp serena_config.template.yml serena_config.yml`. Read the instructions in the config.
3. In the config, check if the path to your project was added. If not, add it to the `projects` section
4. In your project, create a `.serena` if needed and check whether `project.yml` exists there.
5. If no `project.yml` was found, create it using `cp /path/to/serena/myproject.template.yml /path/to/your/project/.serena/project.yml`
6. Read the instructions in `project.yml`. Make sure the `project.yml` has the correct project language configured. 
   Remove the  project_root entry there.
7. Finally, add the Serena MCP server config like this:

```json
   {
       "mcpServers": {
            ...
           "serena": {
               "command": "/abs/path/to/uv",
               "args": ["run", "--directory", "/abs/path/to/serena", "serena-mcp-server", "/path/to/your/project/.serena/project.yml"]
           }
       }
   }

```

```

--------------------------------------------------------------------------------
/src/serena/util/shell.py:
--------------------------------------------------------------------------------

```python
import os
import subprocess

from pydantic import BaseModel

from solidlsp.util.subprocess_util import subprocess_kwargs


class ShellCommandResult(BaseModel):
    stdout: str
    return_code: int
    cwd: str
    stderr: str | None = None


def execute_shell_command(command: str, cwd: str | None = None, capture_stderr: bool = False) -> ShellCommandResult:
    """
    Execute a shell command and return the output.

    :param command: The command to execute.
    :param cwd: The working directory to execute the command in. If None, the current working directory will be used.
    :param capture_stderr: Whether to capture the stderr output.
    :return: The output of the command.
    """
    if cwd is None:
        cwd = os.getcwd()

    process = subprocess.Popen(
        command,
        shell=True,
        stdin=subprocess.DEVNULL,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE if capture_stderr else None,
        text=True,
        encoding="utf-8",
        errors="replace",
        cwd=cwd,
        **subprocess_kwargs(),
    )

    stdout, stderr = process.communicate()
    return ShellCommandResult(stdout=stdout, stderr=stderr, return_code=process.returncode, cwd=cwd)


def subprocess_check_output(args: list[str], encoding: str = "utf-8", strip: bool = True, timeout: float | None = None) -> str:
    output = subprocess.check_output(args, stdin=subprocess.DEVNULL, stderr=subprocess.PIPE, timeout=timeout, env=os.environ.copy(), **subprocess_kwargs()).decode(encoding)  # type: ignore
    if strip:
        output = output.strip()
    return output

```

--------------------------------------------------------------------------------
/test/solidlsp/go/test_go_basic.py:
--------------------------------------------------------------------------------

```python
import os

import pytest

from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils


@pytest.mark.go
class TestGoLanguageServer:
    @pytest.mark.parametrize("language_server", [Language.GO], indirect=True)
    def test_find_symbol(self, language_server: SolidLanguageServer) -> None:
        symbols = language_server.request_full_symbol_tree()
        assert SymbolUtils.symbol_tree_contains_name(symbols, "main"), "main function not found in symbol tree"
        assert SymbolUtils.symbol_tree_contains_name(symbols, "Helper"), "Helper function not found in symbol tree"
        assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoStruct"), "DemoStruct not found in symbol tree"

    @pytest.mark.parametrize("language_server", [Language.GO], indirect=True)
    def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None:
        file_path = os.path.join("main.go")
        symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots()
        helper_symbol = None
        for sym in symbols[0]:
            if sym.get("name") == "Helper":
                helper_symbol = sym
                break
        assert helper_symbol is not None, "Could not find 'Helper' function symbol in main.go"
        sel_start = helper_symbol["selectionRange"]["start"]
        refs = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
        assert any(
            "main.go" in ref.get("relativePath", "") for ref in refs
        ), "main.go should reference Helper (tried all positions in selectionRange)"

```

--------------------------------------------------------------------------------
/scripts/profile_tool_call.py:
--------------------------------------------------------------------------------

```python
import cProfile
from pathlib import Path
from typing import Literal

from sensai.util import logging
from sensai.util.logging import LogTime
from sensai.util.profiling import profiled

from serena.agent import SerenaAgent
from serena.config.serena_config import SerenaConfig
from serena.tools import FindSymbolTool

log = logging.getLogger(__name__)


if __name__ == "__main__":
    logging.configure()

    # The profiler to use:
    # Use pyinstrument for hierarchical profiling output
    # Use cProfile to determine which functions take the most time overall (and use snakeviz to visualize)
    profiler: Literal["pyinstrument", "cprofile"] = "cprofile"

    project_path = Path(__file__).parent.parent  # Serena root

    serena_config = SerenaConfig.from_config_file()
    serena_config.log_level = logging.INFO
    serena_config.jetbrains = False
    serena_config.gui_log_window_enabled = False
    serena_config.web_dashboard = False

    agent = SerenaAgent(str(project_path), serena_config=serena_config)

    # wait for language server to be ready
    agent.execute_task(lambda: log.info("Language server is ready."))

    def tool_call():
        """This is the function we want to profile."""
        # NOTE: We use apply (not apply_ex) to run the tool call directly on the main thread
        with LogTime("Tool call"):
            result = agent.get_tool(FindSymbolTool).apply(name_path="DQN")
        log.info("Tool result:\n%s", result)

    if profiler == "pyinstrument":

        @profiled(log_to_file=True)
        def profiled_tool_call():
            tool_call()

        profiled_tool_call()

    elif profiler == "cprofile":
        cProfile.run("tool_call()", "tool_call.pstat")

```

--------------------------------------------------------------------------------
/test/solidlsp/typescript/test_typescript_basic.py:
--------------------------------------------------------------------------------

```python
import os

import pytest

from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils


@pytest.mark.typescript
class TestTypescriptLanguageServer:
    @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True)
    def test_find_symbol(self, language_server: SolidLanguageServer) -> None:
        symbols = language_server.request_full_symbol_tree()
        assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoClass"), "DemoClass not found in symbol tree"
        assert SymbolUtils.symbol_tree_contains_name(symbols, "helperFunction"), "helperFunction not found in symbol tree"
        assert SymbolUtils.symbol_tree_contains_name(symbols, "printValue"), "printValue method not found in symbol tree"

    @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True)
    def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None:
        file_path = os.path.join("index.ts")
        symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots()
        helper_symbol = None
        for sym in symbols[0]:
            if sym.get("name") == "helperFunction":
                helper_symbol = sym
                break
        assert helper_symbol is not None, "Could not find 'helperFunction' symbol in index.ts"
        sel_start = helper_symbol["selectionRange"]["start"]
        refs = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
        assert any(
            "index.ts" in ref.get("relativePath", "") for ref in refs
        ), "index.ts should reference helperFunction (tried all positions in selectionRange)"

```

--------------------------------------------------------------------------------
/test/resources/repos/bash/test_repo/utils.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash

# Utility functions for bash scripting

# String manipulation functions
function to_uppercase() {
    echo "${1^^}"
}

function to_lowercase() {
    echo "${1,,}"
}

function trim_whitespace() {
    local var="$1"
    var="${var#"${var%%[![:space:]]*}"}"
    var="${var%"${var##*[![:space:]]}"}"   
    echo "$var"
}

# File operations
function backup_file() {
    local file="$1"
    local backup_dir="${2:-./backups}"
    
    if [[ ! -f "$file" ]]; then
        echo "Error: File '$file' does not exist" >&2
        return 1
    fi
    
    mkdir -p "$backup_dir"
    cp "$file" "${backup_dir}/$(basename "$file").$(date +%Y%m%d_%H%M%S).bak"
    echo "Backup created for $file"
}

# Array operations
function contains_element() {
    local element="$1"
    shift
    local array=("$@")
    
    for item in "${array[@]}"; do
        if [[ "$item" == "$element" ]]; then
            return 0
        fi
    done
    return 1
}

# Logging functions
function log_message() {
    local level="$1"
    local message="$2"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    case "$level" in
        "ERROR")
            echo "[$timestamp] ERROR: $message" >&2
            ;;
        "WARN")
            echo "[$timestamp] WARN: $message" >&2
            ;;
        "INFO")
            echo "[$timestamp] INFO: $message"
            ;;
        "DEBUG")
            [[ "${DEBUG:-false}" == "true" ]] && echo "[$timestamp] DEBUG: $message"
            ;;
        *)
            echo "[$timestamp] $message"
            ;;
    esac
}

# Validation functions
function is_valid_email() {
    local email="$1"
    [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]
}

function is_number() {
    [[ $1 =~ ^[0-9]+$ ]]
}

```

--------------------------------------------------------------------------------
/test/solidlsp/erlang/test_erlang_basic.py:
--------------------------------------------------------------------------------

```python
"""
Basic integration tests for the Erlang language server functionality.

These tests validate the functionality of the language server APIs
like request_references using the test repository.
"""

import pytest

from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language

from . import ERLANG_LS_UNAVAILABLE, ERLANG_LS_UNAVAILABLE_REASON


@pytest.mark.erlang
@pytest.mark.skipif(ERLANG_LS_UNAVAILABLE, reason=f"Erlang LS not available: {ERLANG_LS_UNAVAILABLE_REASON}")
class TestErlangLanguageServerBasics:
    """Test basic functionality of the Erlang language server."""

    @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True)
    def test_language_server_initialization(self, language_server: SolidLanguageServer) -> None:
        """Test that the Erlang language server initializes properly."""
        assert language_server is not None
        assert language_server.language == Language.ERLANG

    @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True)
    def test_document_symbols(self, language_server: SolidLanguageServer) -> None:
        """Test document symbols retrieval for Erlang files."""
        try:
            file_path = "hello.erl"
            symbols_tuple = language_server.request_document_symbols(file_path).get_all_symbols_and_roots()
            assert isinstance(symbols_tuple, tuple)
            assert len(symbols_tuple) == 2

            all_symbols, root_symbols = symbols_tuple
            assert isinstance(all_symbols, list)
            assert isinstance(root_symbols, list)
        except Exception as e:
            if "not fully initialized" in str(e):
                pytest.skip("Erlang language server not fully initialized")
            else:
                raise

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/nested_base.py:
--------------------------------------------------------------------------------

```python
"""
Module to test parsing of classes with nested module paths in base classes.
"""

from typing import Generic, TypeVar

T = TypeVar("T")


class BaseModule:
    """Base module class for nested module tests."""


class SubModule:
    """Sub-module class for nested paths."""

    class NestedBase:
        """Nested base class."""

        def base_method(self):
            """Base method."""
            return "base"

        class NestedLevel2:
            """Nested level 2."""

            def nested_level_2_method(self):
                """Nested level 2 method."""
                return "nested_level_2"

    class GenericBase(Generic[T]):
        """Generic nested base class."""

        def generic_method(self, value: T) -> T:
            """Generic method."""
            return value


# Classes extending base classes with single-level nesting
class FirstLevel(SubModule):
    """Class extending a class from a nested module path."""

    def first_level_method(self):
        """First level method."""
        return "first"


# Classes extending base classes with multi-level nesting
class TwoLevel(SubModule.NestedBase):
    """Class extending a doubly-nested base class."""

    def multi_level_method(self):
        """Multi-level method."""
        return "multi"

    def base_method(self):
        """Override of base method."""
        return "overridden"


class ThreeLevel(SubModule.NestedBase.NestedLevel2):
    """Class extending a triply-nested base class."""

    def three_level_method(self):
        """Three-level method."""
        return "three"


# Class extending a generic base class with nesting
class GenericExtension(SubModule.GenericBase[str]):
    """Class extending a generic nested base class."""

    def generic_extension_method(self, text: str) -> str:
        """Extension method."""
        return f"Extended: {text}"

```

--------------------------------------------------------------------------------
/src/serena/util/inspection.py:
--------------------------------------------------------------------------------

```python
import logging
import os
from collections.abc import Generator
from typing import TypeVar

from serena.util.file_system import find_all_non_ignored_files
from solidlsp.ls_config import Language

T = TypeVar("T")

log = logging.getLogger(__name__)


def iter_subclasses(cls: type[T], recursive: bool = True) -> Generator[type[T], None, None]:
    """Iterate over all subclasses of a class. If recursive is True, also iterate over all subclasses of all subclasses."""
    for subclass in cls.__subclasses__():
        yield subclass
        if recursive:
            yield from iter_subclasses(subclass, recursive)


def determine_programming_language_composition(repo_path: str) -> dict[str, float]:
    """
    Determine the programming language composition of a repository.

    :param repo_path: Path to the repository to analyze

    :return: Dictionary mapping language names to percentages of files matching each language
    """
    all_files = find_all_non_ignored_files(repo_path)

    if not all_files:
        return {}

    # Count files for each language
    language_counts: dict[str, int] = {}
    total_files = len(all_files)

    for language in Language.iter_all(include_experimental=False):
        matcher = language.get_source_fn_matcher()
        count = 0

        for file_path in all_files:
            # Use just the filename for matching, not the full path
            filename = os.path.basename(file_path)
            if matcher.is_relevant_filename(filename):
                count += 1

        if count > 0:
            language_counts[str(language)] = count

    # Convert counts to percentages
    language_percentages: dict[str, float] = {}
    for language_name, count in language_counts.items():
        percentage = (count / total_files) * 100
        language_percentages[language_name] = round(percentage, 2)

    return language_percentages

```

--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------

```yaml
name: Build and Push Docker Images

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read
      packages: write

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

    - name: Log in to Container Registry
      if: github.event_name != 'pull_request'
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern={{version}}
          type=semver,pattern={{major}}.{{minor}}
          type=raw,value=latest,enable={{is_default_branch}}

    - name: Build and push production image
      uses: docker/build-push-action@v5
      with:
        context: .
        target: production
        platforms: linux/amd64,linux/arm64
        push: ${{ github.event_name != 'pull_request' }}
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

    - name: Build and push development image
      uses: docker/build-push-action@v5
      with:
        context: .
        target: development
        platforms: linux/amd64,linux/arm64
        push: ${{ github.event_name != 'pull_request' }}
        tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dev
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max
```

--------------------------------------------------------------------------------
/src/solidlsp/ls_exceptions.py:
--------------------------------------------------------------------------------

```python
"""
This module contains the exceptions raised by the framework.
"""

from solidlsp.ls_config import Language


class SolidLSPException(Exception):
    def __init__(self, message: str, cause: Exception | None = None) -> None:
        """
        Initializes the exception with the given message.

        :param message: the message describing the exception
        :param cause: the original exception that caused this exception, if any.
            For exceptions raised during request handling, this is typically
                * an LSPError for errors returned by the LSP server
                * LanguageServerTerminatedException for errors due to the language server having terminated.
        """
        self.cause = cause
        super().__init__(message)

    def is_language_server_terminated(self) -> bool:
        """
        :return: True if the exception is caused by the language server having terminated as indicated
            by the causing exception being an instance of LanguageServerTerminatedException.
        """
        from .ls_handler import LanguageServerTerminatedException

        return isinstance(self.cause, LanguageServerTerminatedException)

    def get_affected_language(self) -> Language | None:
        """
        :return: the affected language for the case where the exception is caused by the language server having terminated
        """
        from .ls_handler import LanguageServerTerminatedException

        if isinstance(self.cause, LanguageServerTerminatedException):
            return self.cause.language
        return None

    def __str__(self) -> str:
        """
        Returns a string representation of the exception.
        """
        s = super().__str__()
        if self.cause:
            if "\n" in s:
                s += "\n"
            else:
                s += " "
            s += f"(caused by {self.cause})"
        return s

```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/ide-assistant.yml:
--------------------------------------------------------------------------------

```yaml
description: Non-symbolic editing tools and general shell tool are excluded
prompt: |
  You are running in IDE assistant context where file operations, basic (line-based) edits and reads, 
  and shell commands are handled by your own, internal tools.
  The initial instructions and the current config inform you on which tools are available to you,
  and how to use them.
  Don't attempt to use any excluded tools, instead rely on your own internal tools
  for achieving the basic file or shell operations.
  
  If serena's tools can be used for achieving your task, 
  you should prioritize them. In particular, it is important that you avoid reading entire source code files,
  unless it is strictly necessary! Instead, for exploring and reading code in a token-efficient manner, 
  you should use serena's overview and symbolic search tools. 
  Before reading a full file, it is usually best to first explore the file using the symbol_overview tool, 
  and then make targeted reads using find_symbol and other symbolic tools.
  For non-code files or for reads where you don't know the symbol's name path, you can use the pattern searching tool,
  and read full files only as a last resort.

excluded_tools:
  - create_text_file
  - read_file
  - execute_shell_command
  - prepare_for_new_conversation
  - replace_content

tool_description_overrides: {}

# whether to assume that Serena shall only work on a single project in this context (provided that a project is given
# when Serena is started).
# If set to true and a project is provided at startup, the set of tools is limited to those required by the project's
# concrete configuration, and other tools are excluded completely, allowing the set of tools to be minimal.
# Tools explicitly disabled by the project will not be available at all.
# The `activate_project` tool is always disabled in this case, as project switching cannot be allowed.
single_project: true

```

--------------------------------------------------------------------------------
/docs/01-about/050_acknowledgements.md:
--------------------------------------------------------------------------------

```markdown
# Acknowledgements

## Sponsors

We are very grateful to our [sponsors](https://github.com/sponsors/oraios), who help us drive Serena's development. 
The core team (the founders of [Oraios AI](https://oraios-ai.de/)) put in a lot of work in order to turn Serena into a useful open source project.
So far, there is no business model behind this project, and sponsors are our only source of income from it.

Sponsors help us dedicate more time to the project, managing contributions, and working on larger features (like better tooling based on more advanced
LSP features, VSCode integration, debugging via the DAP, and several others).
If you find this project useful to your work, or would like to accelerate the development of Serena, consider becoming a sponsor.

We are proud to announce that the Visual Studio Code team, together with Microsoft’s Open Source Programs Office and GitHub Open Source
have decided to sponsor Serena with a one-time contribution!

## Community Contributions

A significant part of Serena, especially support for various languages, was contributed by the open source community.
We are very grateful for the many contributors who made this possible and who played an important role in making Serena
what it is today.

## Technologies

We built Serena on top of multiple existing open-source technologies, the most important ones being:

1. [multilspy](https://github.com/microsoft/multilspy).
   A library which wraps language server implementations and adapts them for interaction via Python
   and which provided the basis for our library Solid-LSP (src/solidlsp).
   Solid-LSP provides pure synchronous LSP calls and extends the original library with the symbolic logic
   that Serena required.
2. [Python MCP SDK](https://github.com/modelcontextprotocol/python-sdk)
3. All the language servers that we use through Solid-LSP.

Without these projects, Serena would not have been possible (or would have been significantly more difficult to build).

```

--------------------------------------------------------------------------------
/src/solidlsp/lsp_protocol_handler/lsp_constants.py:
--------------------------------------------------------------------------------

```python
"""
This module contains constants used in the LSP protocol.
"""


class LSPConstants:
    """
    This class contains constants used in the LSP protocol.
    """

    # the key for uri used to represent paths
    URI = "uri"

    # the key for range, which is a from and to position within a text document
    RANGE = "range"

    # A key used in LocationLink type, used as the span of the origin link
    ORIGIN_SELECTION_RANGE = "originSelectionRange"

    # A key used in LocationLink type, used as the target uri of the link
    TARGET_URI = "targetUri"

    # A key used in LocationLink type, used as the target range of the link
    TARGET_RANGE = "targetRange"

    # A key used in LocationLink type, used as the target selection range of the link
    TARGET_SELECTION_RANGE = "targetSelectionRange"

    # key for the textDocument field in the request
    TEXT_DOCUMENT = "textDocument"

    # key used to represent the language a document is in - "java", "csharp", etc.
    LANGUAGE_ID = "languageId"

    # key used to represent the version of a document (a shared value between the client and server)
    VERSION = "version"

    # key used to represent the text of a document being sent from the client to the server on open
    TEXT = "text"

    # key used to represent a position (line and colnum) within a text document
    POSITION = "position"

    # key used to represent the line number of a position
    LINE = "line"

    # key used to represent the column number of a position
    CHARACTER = "character"

    # key used to represent the changes made to a document
    CONTENT_CHANGES = "contentChanges"

    # key used to represent name of symbols
    NAME = "name"

    # key used to represent the kind of symbols
    KIND = "kind"

    # key used to represent children in document symbols
    CHILDREN = "children"

    # key used to represent the location in symbols
    LOCATION = "location"

    # Severity level of the diagnostic
    SEVERITY = "severity"

    # The message of the diagnostic
    MESSAGE = "message"

```

--------------------------------------------------------------------------------
/src/serena/tools/cmd_tools.py:
--------------------------------------------------------------------------------

```python
"""
Tools supporting the execution of (external) commands
"""

import os.path

from serena.tools import Tool, ToolMarkerCanEdit
from serena.util.shell import execute_shell_command


class ExecuteShellCommandTool(Tool, ToolMarkerCanEdit):
    """
    Executes a shell command.
    """

    def apply(
        self,
        command: str,
        cwd: str | None = None,
        capture_stderr: bool = True,
        max_answer_chars: int = -1,
    ) -> str:
        """
        Execute a shell command and return its output. If there is a memory about suggested commands, read that first.
        Never execute unsafe shell commands!
        IMPORTANT: Do not use this tool to start
          * long-running processes (e.g. servers) that are not intended to terminate quickly,
          * processes that require user interaction.

        :param command: the shell command to execute
        :param cwd: the working directory to execute the command in. If None, the project root will be used.
        :param capture_stderr: whether to capture and return stderr output
        :param max_answer_chars: if the output is longer than this number of characters,
            no content will be returned. -1 means using the default value, don't adjust unless there is no other way to get the content
            required for the task.
        :return: a JSON object containing the command's stdout and optionally stderr output
        """
        if cwd is None:
            _cwd = self.get_project_root()
        else:
            if os.path.isabs(cwd):
                _cwd = cwd
            else:
                _cwd = os.path.join(self.get_project_root(), cwd)
                if not os.path.isdir(_cwd):
                    raise FileNotFoundError(
                        f"Specified a relative working directory ({cwd}), but the resulting path is not a directory: {_cwd}"
                    )

        result = execute_shell_command(command, cwd=_cwd, capture_stderr=capture_stderr)
        result = result.json()
        return self._limit_length(result, max_answer_chars)

```

--------------------------------------------------------------------------------
/src/serena/resources/config/contexts/chatgpt.yml:
--------------------------------------------------------------------------------

```yaml
description: A configuration specific for chatgpt, which has a limit of 30 tools and requires short descriptions.
prompt: |
  You are running in desktop app context where the tools give you access to the code base as well as some
  access to the file system, if configured. You interact with the user through a chat interface that is separated
  from the code base. As a consequence, if you are in interactive mode, your communication with the user should
  involve high-level thinking and planning as well as some summarization of any code edits that you make.
  For viewing the code edits the user will view them in a separate code editor window, and the back-and-forth
  between the chat and the code editor should be minimized as well as facilitated by you.
  If complex changes have been made, advise the user on how to review them in the code editor.
  If complex relationships that the user asked for should be visualized or explained, consider creating
  a diagram in addition to your text-based communication. Note that in the chat interface you have various rendering
  options for text, html, and mermaid diagrams, as has been explained to you in your initial instructions.
excluded_tools: []
included_optional_tools:
  - switch_modes

tool_description_overrides:
  find_symbol: |
    Retrieves symbols matching `name_path_pattern` in a file.
    Use `depth > 0` to include children. `name_path_pattern` can be: "foo": any symbol named "foo"; "foo/bar": "bar" within "foo"; "/foo/bar": only top-level "foo/bar"
  replace_content: |
    Replaces content in files. Preferred for smaller edits where symbol-level tools aren't appropriate.
    Use mode "regex" with wildcards (.*?) to match large sections efficiently: "beginning.*?end" instead of specifying exact content.
    Essential for multi-line replacements.
  search_for_pattern: |
    Flexible pattern search across codebase. Prefer symbolic operations when possible.
    Uses DOTALL matching. Use non-greedy quantifiers (.*?) to avoid over-matching.
    Supports file filtering via globs and code-only restriction.
```

--------------------------------------------------------------------------------
/src/serena/util/thread.py:
--------------------------------------------------------------------------------

```python
import threading
from collections.abc import Callable
from enum import Enum
from typing import Generic, TypeVar

from sensai.util.string import ToStringMixin


class TimeoutException(Exception):
    def __init__(self, message: str, timeout: float) -> None:
        super().__init__(message)
        self.timeout = timeout


T = TypeVar("T")


class ExecutionResult(Generic[T], ToStringMixin):

    class Status(Enum):
        SUCCESS = "success"
        TIMEOUT = "timeout"
        EXCEPTION = "error"

    def __init__(self) -> None:
        self.result_value: T | None = None
        self.status: ExecutionResult.Status | None = None
        self.exception: Exception | None = None

    def set_result_value(self, value: T) -> None:
        self.result_value = value
        self.status = ExecutionResult.Status.SUCCESS

    def set_timed_out(self, exception: TimeoutException) -> None:
        self.exception = exception
        self.status = ExecutionResult.Status.TIMEOUT

    def set_exception(self, exception: Exception) -> None:
        self.exception = exception
        self.status = ExecutionResult.Status.EXCEPTION


def execute_with_timeout(func: Callable[[], T], timeout: float, function_name: str) -> ExecutionResult[T]:
    """
    Executes the given function with a timeout

    :param func: the function to execute
    :param timeout: the timeout in seconds
    :param function_name: the name of the function (for error messages)
    :returns: the execution result
    """
    execution_result: ExecutionResult[T] = ExecutionResult()

    def target() -> None:
        try:
            value = func()
            execution_result.set_result_value(value)
        except Exception as e:
            execution_result.set_exception(e)

    thread = threading.Thread(target=target, daemon=True)
    thread.start()
    thread.join(timeout=timeout)

    if thread.is_alive():
        timeout_exception = TimeoutException(f"Execution of '{function_name}' timed out after {timeout} seconds.", timeout)
        execution_result.set_timed_out(timeout_exception)

    return execution_result

```

--------------------------------------------------------------------------------
/docs/02-usage/999_additional-usage.md:
--------------------------------------------------------------------------------

```markdown
# Additional Usage Pointers

## Prompting Strategies

We found that it is often a good idea to spend some time conceptualizing and planning a task
before actually implementing it, especially for non-trivial task. This helps both in achieving
better results and in increasing the feeling of control and staying in the loop. You can
make a detailed plan in one session, where Serena may read a lot of your code to build up the context,
and then continue with the implementation in another (potentially after creating suitable memories).

## Running Out of Context

For long and complicated tasks, or tasks where Serena has read a lot of content, you
may come close to the limits of context tokens. In that case, it is often a good idea to continue
in a new conversation. Serena has a dedicated tool to create a summary of the current state
of the progress and all relevant info for continuing it. You can request to create this summary and
write it to a memory. Then, in a new conversation, you can just ask Serena to read the memory and
continue with the task. In our experience, this worked really well. On the up-side, since in a
single session there is no summarization involved, Serena does not usually get lost (unlike some
other agents that summarize under the hood), and it is also instructed to occasionally check whether
it's on the right track.

Serena instructs the LLM to be economical in general, so the problem of running out of context
should not occur too often, unless the task is very large or complicated.

## Serena and Git Worktrees

[git-worktree](https://git-scm.com/docs/git-worktree) can be an excellent way to parallelize your work. More on this in [Anthropic: Run parallel Claude Code sessions with Git worktrees](https://docs.claude.com/en/docs/claude-code/common-workflows#run-parallel-claude-code-sessions-with-git-worktrees).

When it comes to serena AND git-worktree AND larger projects (that take longer to index), 
the recommended way is to COPY your `$ORIG_PROJECT/.serena/cache` to `$GIT_WORKTREE/.serena/cache`. 
Perform [pre-indexing of your project](indexing) to avoid having to re-index per each worktree you create. 

```

--------------------------------------------------------------------------------
/test/resources/repos/bash/test_repo/config.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash

# Configuration script for project setup

# Environment variables
export PROJECT_NAME="bash-test-project"
export PROJECT_VERSION="1.0.0"
export LOG_LEVEL="INFO"
export CONFIG_DIR="./config"

# Default settings
DEFAULT_TIMEOUT=30
DEFAULT_RETRIES=3
DEFAULT_PORT=8080

# Configuration arrays
declare -A ENVIRONMENTS=(
    ["dev"]="development"
    ["prod"]="production"
    ["test"]="testing"
)

declare -A DATABASE_CONFIGS=(
    ["host"]="localhost"
    ["port"]="5432"
    ["name"]="myapp_db"
    ["user"]="dbuser"
)

# Function to load configuration
load_config() {
    local env="${1:-dev}"
    local config_file="${CONFIG_DIR}/${env}.conf"
    
    if [[ -f "$config_file" ]]; then
        echo "Loading configuration from $config_file"
        source "$config_file"
    else
        echo "Warning: Configuration file $config_file not found, using defaults"
    fi
}

# Function to validate configuration
validate_config() {
    local errors=0
    
    if [[ -z "$PROJECT_NAME" ]]; then
        echo "Error: PROJECT_NAME is not set" >&2
        ((errors++))
    fi
    
    if [[ -z "$PROJECT_VERSION" ]]; then
        echo "Error: PROJECT_VERSION is not set" >&2
        ((errors++))
    fi
    
    if [[ $DEFAULT_PORT -lt 1024 || $DEFAULT_PORT -gt 65535 ]]; then
        echo "Error: Invalid port number $DEFAULT_PORT" >&2
        ((errors++))
    fi
    
    return $errors
}

# Function to print configuration
print_config() {
    echo "=== Current Configuration ==="
    echo "Project Name: $PROJECT_NAME"
    echo "Version: $PROJECT_VERSION"
    echo "Log Level: $LOG_LEVEL"
    echo "Default Port: $DEFAULT_PORT"
    echo "Default Timeout: $DEFAULT_TIMEOUT"
    echo "Default Retries: $DEFAULT_RETRIES"
    
    echo "\n=== Environments ==="
    for env in "${!ENVIRONMENTS[@]}"; do
        echo "  $env: ${ENVIRONMENTS[$env]}"
    done
    
    echo "\n=== Database Configuration ==="
    for key in "${!DATABASE_CONFIGS[@]}"; do
        echo "  $key: ${DATABASE_CONFIGS[$key]}"
    done
}

# Initialize configuration if this script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    load_config "$1"
    validate_config
    print_config
fi

```

--------------------------------------------------------------------------------
/test/solidlsp/scala/test_scala_language_server.py:
--------------------------------------------------------------------------------

```python
import os

import pytest

from solidlsp.language_servers.scala_language_server import ScalaLanguageServer
from solidlsp.ls_config import Language, LanguageServerConfig
from solidlsp.settings import SolidLSPSettings

pytest.skip("Scala must be compiled for these tests to run through, which is a huge hassle", allow_module_level=True)

MAIN_FILE_PATH = os.path.join("src", "main", "scala", "com", "example", "Main.scala")

pytestmark = pytest.mark.scala


@pytest.fixture(scope="module")
def scala_ls():
    repo_root = os.path.abspath("test/resources/repos/scala")
    config = LanguageServerConfig(code_language=Language.SCALA)
    solidlsp_settings = SolidLSPSettings()
    ls = ScalaLanguageServer(config, repo_root, solidlsp_settings)

    with ls.start_server():
        yield ls


def test_scala_document_symbols(scala_ls):
    """Test document symbols for Main.scala"""
    symbols, _ = scala_ls.request_document_symbols(MAIN_FILE_PATH).get_all_symbols_and_roots()
    symbol_names = [s["name"] for s in symbols]
    assert symbol_names[0] == "com.example"
    assert symbol_names[1] == "Main"
    assert symbol_names[2] == "main"
    assert symbol_names[3] == "result"
    assert symbol_names[4] == "sum"
    assert symbol_names[5] == "add"


def test_scala_references_within_same_file(scala_ls):
    """Test finding references within the same file."""
    definitions = scala_ls.request_definition(MAIN_FILE_PATH, 12, 23)
    first_def = definitions[0]
    assert first_def["uri"].endswith("Main.scala")
    assert first_def["range"]["start"]["line"] == 16
    assert first_def["range"]["start"]["character"] == 6
    assert first_def["range"]["end"]["line"] == 16
    assert first_def["range"]["end"]["character"] == 9


def test_scala_find_definition_and_references_across_files(scala_ls):
    definitions = scala_ls.request_definition(MAIN_FILE_PATH, 8, 25)
    assert len(definitions) == 1

    first_def = definitions[0]
    assert first_def["uri"].endswith("Utils.scala")
    assert first_def["range"]["start"]["line"] == 7
    assert first_def["range"]["start"]["character"] == 6
    assert first_def["range"]["end"]["line"] == 7
    assert first_def["range"]["end"]["character"] == 14

```

--------------------------------------------------------------------------------
/src/serena/util/exception.py:
--------------------------------------------------------------------------------

```python
import os
import sys

from serena.agent import log


def is_headless_environment() -> bool:
    """
    Detect if we're running in a headless environment where GUI operations would fail.

    Returns True if:
    - No DISPLAY variable on Linux/Unix
    - Running in SSH session
    - Running in WSL without X server
    - Running in Docker container
    """
    # Check if we're on Windows - GUI usually works there
    if sys.platform == "win32":
        return False

    # Check for DISPLAY variable (required for X11)
    if not os.environ.get("DISPLAY"):  # type: ignore
        return True

    # Check for SSH session
    if os.environ.get("SSH_CONNECTION") or os.environ.get("SSH_CLIENT"):
        return True

    # Check for common CI/container environments
    if os.environ.get("CI") or os.environ.get("CONTAINER") or os.path.exists("/.dockerenv"):
        return True

    # Check for WSL (only on Unix-like systems where os.uname exists)
    if hasattr(os, "uname"):
        if "microsoft" in os.uname().release.lower():
            # In WSL, even with DISPLAY set, X server might not be running
            # This is a simplified check - could be improved
            return True

    return False


def show_fatal_exception_safe(e: Exception) -> None:
    """
    Shows the given exception in the GUI log viewer on the main thread and ensures that the exception is logged or at
    least printed to stderr.
    """
    # Log the error and print it to stderr
    log.error(f"Fatal exception: {e}", exc_info=e)
    print(f"Fatal exception: {e}", file=sys.stderr)

    # Don't attempt GUI in headless environments
    if is_headless_environment():
        log.debug("Skipping GUI error display in headless environment")
        return

    # attempt to show the error in the GUI
    try:
        # NOTE: The import can fail on macOS if Tk is not available (depends on Python interpreter installation, which uv
        #   used as a base); while tkinter as such is always available, its dependencies can be unavailable on macOS.
        from serena.gui_log_viewer import show_fatal_exception

        show_fatal_exception(e)
    except Exception as gui_error:
        log.debug(f"Failed to show GUI error dialog: {gui_error}")

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/services.py:
--------------------------------------------------------------------------------

```python
"""
Services module demonstrating function usage and dependencies.
"""

from typing import Any

from .models import Item, User


class UserService:
    """Service for user-related operations"""

    def __init__(self, user_db: dict[str, User] | None = None):
        self.users = user_db or {}

    def create_user(self, id: str, name: str, email: str) -> User:
        """Create a new user and store it"""
        if id in self.users:
            raise ValueError(f"User with ID {id} already exists")

        user = User(id=id, name=name, email=email)
        self.users[id] = user
        return user

    def get_user(self, id: str) -> User | None:
        """Get a user by ID"""
        return self.users.get(id)

    def list_users(self) -> list[User]:
        """Get a list of all users"""
        return list(self.users.values())

    def delete_user(self, id: str) -> bool:
        """Delete a user by ID"""
        if id in self.users:
            del self.users[id]
            return True
        return False


class ItemService:
    """Service for item-related operations"""

    def __init__(self, item_db: dict[str, Item] | None = None):
        self.items = item_db or {}

    def create_item(self, id: str, name: str, price: float, category: str) -> Item:
        """Create a new item and store it"""
        if id in self.items:
            raise ValueError(f"Item with ID {id} already exists")

        item = Item(id=id, name=name, price=price, category=category)
        self.items[id] = item
        return item

    def get_item(self, id: str) -> Item | None:
        """Get an item by ID"""
        return self.items.get(id)

    def list_items(self, category: str | None = None) -> list[Item]:
        """List all items, optionally filtered by category"""
        if category:
            return [item for item in self.items.values() if item.category == category]
        return list(self.items.values())


# Factory function for services
def create_service_container() -> dict[str, Any]:
    """Create a container with all services"""
    container = {"user_service": UserService(), "item_service": ItemService()}
    return container


user_var_str = "user_var"


user_service = UserService()
user_service.create_user("1", "Alice", "[email protected]")

```

--------------------------------------------------------------------------------
/test/solidlsp/ruby/test_ruby_basic.py:
--------------------------------------------------------------------------------

```python
import os
from pathlib import Path

import pytest

from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils


@pytest.mark.ruby
class TestRubyLanguageServer:
    @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True)
    def test_find_symbol(self, language_server: SolidLanguageServer) -> None:
        symbols = language_server.request_full_symbol_tree()
        assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoClass"), "DemoClass not found in symbol tree"
        assert SymbolUtils.symbol_tree_contains_name(symbols, "helper_function"), "helper_function not found in symbol tree"
        assert SymbolUtils.symbol_tree_contains_name(symbols, "print_value"), "print_value not found in symbol tree"

    @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True)
    def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None:
        file_path = os.path.join("main.rb")
        symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots()
        helper_symbol = None
        for sym in symbols[0]:
            if sym.get("name") == "helper_function":
                helper_symbol = sym
                break
        print(helper_symbol)
        assert helper_symbol is not None, "Could not find 'helper_function' symbol in main.rb"

    @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True)
    @pytest.mark.parametrize("repo_path", [Language.RUBY], indirect=True)
    def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
        # Test finding Calculator.add method definition from line 17: Calculator.new.add(demo.value, 10)
        definition_location_list = language_server.request_definition(
            str(repo_path / "main.rb"), 16, 17
        )  # add method at line 17 (0-indexed 16), position 17

        assert len(definition_location_list) == 1
        definition_location = definition_location_list[0]
        print(f"Found definition: {definition_location}")
        assert definition_location["uri"].endswith("lib.rb")
        assert definition_location["range"]["start"]["line"] == 1  # add method on line 2 (0-indexed 1)

```

--------------------------------------------------------------------------------
/src/serena/constants.py:
--------------------------------------------------------------------------------

```python
from pathlib import Path

_repo_root_path = Path(__file__).parent.parent.parent.resolve()
_serena_pkg_path = Path(__file__).parent.resolve()

SERENA_MANAGED_DIR_NAME = ".serena"
_serena_in_home_managed_dir = Path.home() / ".serena"

SERENA_MANAGED_DIR_IN_HOME = str(_serena_in_home_managed_dir)

# TODO: Path-related constants should be moved to SerenaPaths; don't add further constants here.
REPO_ROOT = str(_repo_root_path)
PROMPT_TEMPLATES_DIR_INTERNAL = str(_serena_pkg_path / "resources" / "config" / "prompt_templates")
PROMPT_TEMPLATES_DIR_IN_USER_HOME = str(_serena_in_home_managed_dir / "prompt_templates")
SERENAS_OWN_CONTEXT_YAMLS_DIR = str(_serena_pkg_path / "resources" / "config" / "contexts")
"""The contexts that are shipped with the Serena package, i.e. the default contexts."""
USER_CONTEXT_YAMLS_DIR = str(_serena_in_home_managed_dir / "contexts")
"""Contexts defined by the user. If a name of a context matches a name of a context in SERENAS_OWN_CONTEXT_YAMLS_DIR, the user context will override the default one."""
SERENAS_OWN_MODE_YAMLS_DIR = str(_serena_pkg_path / "resources" / "config" / "modes")
"""The modes that are shipped with the Serena package, i.e. the default modes."""
USER_MODE_YAMLS_DIR = str(_serena_in_home_managed_dir / "modes")
"""Modes defined by the user. If a name of a mode matches a name of a mode in SERENAS_OWN_MODE_YAMLS_DIR, the user mode will override the default one."""
INTERNAL_MODE_YAMLS_DIR = str(_serena_pkg_path / "resources" / "config" / "internal_modes")
"""Internal modes, never overridden by user modes."""
SERENA_DASHBOARD_DIR = str(_serena_pkg_path / "resources" / "dashboard")
SERENA_ICON_DIR = str(_serena_pkg_path / "resources" / "icons")

DEFAULT_SOURCE_FILE_ENCODING = "utf-8"
"""The default encoding assumed for project source files."""
DEFAULT_CONTEXT = "desktop-app"
DEFAULT_MODES = ("interactive", "editing")

SERENA_FILE_ENCODING = "utf-8"
"""The encoding used for Serena's own files, such as configuration files and memories."""

PROJECT_TEMPLATE_FILE = str(_serena_pkg_path / "resources" / "project.template.yml")
SERENA_CONFIG_TEMPLATE_FILE = str(_serena_pkg_path / "resources" / "serena_config.template.yml")

SERENA_LOG_FORMAT = "%(levelname)-5s %(asctime)-15s [%(threadName)s] %(name)s:%(funcName)s:%(lineno)d - %(message)s"

```

--------------------------------------------------------------------------------
/test/solidlsp/julia/test_julia_basic.py:
--------------------------------------------------------------------------------

```python
import pytest

from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import Language


@pytest.mark.julia
class TestJuliaLanguageServer:
    @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True)
    def test_julia_symbols(self, language_server: SolidLanguageServer):
        """
        Test if we can find the top-level symbols in the main.jl file.
        """
        all_symbols, _ = language_server.request_document_symbols("main.jl").get_all_symbols_and_roots()
        symbol_names = {s["name"] for s in all_symbols}
        assert "calculate_sum" in symbol_names
        assert "main" in symbol_names

    @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True)
    def test_julia_within_file_references(self, language_server: SolidLanguageServer):
        """
        Test finding references to a function within the same file.
        """
        # Find references to 'calculate_sum' - the function name starts at line 2, column 9
        # LSP uses 0-based indexing
        references = language_server.request_references("main.jl", line=2, column=9)

        # Should find at least the definition and the call site
        assert len(references) >= 1, f"Expected at least 1 reference, got {len(references)}"

        # Verify at least one reference is in main.jl
        reference_paths = [ref["relativePath"] for ref in references]
        assert "main.jl" in reference_paths

    @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True)
    def test_julia_cross_file_references(self, language_server: SolidLanguageServer):
        """
        Test finding references to a function defined in another file.
        """
        # The 'say_hello' function name starts at line 1, column 13 in lib/helper.jl
        # LSP uses 0-based indexing
        references = language_server.request_references("lib/helper.jl", line=1, column=13)

        # Should find at least the call site in main.jl
        assert len(references) >= 1, f"Expected at least 1 reference, got {len(references)}"

        # Verify at least one reference points to the usage
        reference_paths = [ref["relativePath"] for ref in references]
        # The reference might be in either file (definition or usage)
        assert "main.jl" in reference_paths or "lib/helper.jl" in reference_paths

```

--------------------------------------------------------------------------------
/test/resources/repos/python/test_repo/test_repo/overloaded.py:
--------------------------------------------------------------------------------

```python
"""
Module demonstrating function and method overloading with typing.overload
"""

from typing import Any, overload


# Example of function overloading
@overload
def process_data(data: str) -> dict[str, str]: ...


@overload
def process_data(data: int) -> dict[str, int]: ...


@overload
def process_data(data: list[str | int]) -> dict[str, list[str | int]]: ...


def process_data(data: str | int | list[str | int]) -> dict[str, Any]:
    """
    Process data based on its type.

    - If string: returns a dict with 'value': <string>
    - If int: returns a dict with 'value': <int>
    - If list: returns a dict with 'value': <list>
    """
    return {"value": data}


# Class with overloaded methods
class DataProcessor:
    """
    A class demonstrating method overloading.
    """

    @overload
    def transform(self, input_value: str) -> str: ...

    @overload
    def transform(self, input_value: int) -> int: ...

    @overload
    def transform(self, input_value: list[Any]) -> list[Any]: ...

    def transform(self, input_value: str | int | list[Any]) -> str | int | list[Any]:
        """
        Transform input based on its type.

        - If string: returns the string in uppercase
        - If int: returns the int multiplied by 2
        - If list: returns the list sorted
        """
        if isinstance(input_value, str):
            return input_value.upper()
        elif isinstance(input_value, int):
            return input_value * 2
        elif isinstance(input_value, list):
            try:
                return sorted(input_value)
            except TypeError:
                return input_value
        return input_value

    @overload
    def fetch(self, id: int) -> dict[str, Any]: ...

    @overload
    def fetch(self, id: str, cache: bool = False) -> dict[str, Any] | None: ...

    def fetch(self, id: int | str, cache: bool = False) -> dict[str, Any] | None:
        """
        Fetch data for a given ID.

        Args:
            id: The ID to fetch, either numeric or string
            cache: Whether to use cache for string IDs

        Returns:
            Data dictionary or None if not found

        """
        # Implementation would actually fetch data
        if isinstance(id, int):
            return {"id": id, "type": "numeric"}
        else:
            return {"id": id, "type": "string", "cached": cache}

```

--------------------------------------------------------------------------------
/docs/01-about/040_comparison-to-other-agents.md:
--------------------------------------------------------------------------------

```markdown
# Comparison with Other Coding Agents

To our knowledge, Serena is the first fully-featured coding agent where the
entire functionality is made available through an MCP server, 
thus not requiring additional API keys or subscriptions if access to an LLM
is already available through an MCP-compatible client.

## Subscription-Based Coding Agents

Many prominent subscription-based coding agents are parts of IDEs like
Windsurf, Cursor and VSCode.
Serena's functionality is similar to Cursor's Agent, Windsurf's Cascade or
VSCode's agent mode.

Serena has the advantage of not requiring a subscription.

More technical differences are:

* Serena navigates and edits code using a language server, so it has a symbolic
  understanding of the code.
  IDE-based tools often use a text search-based or purely text file-based approach, which is often
  less powerful, especially for large codebases.
* Serena is not bound to a specific interface (IDE or CLI).
  Serena's MCP server can be used with any MCP client (including some IDEs).
* Serena is not bound to a specific large language model or API.
* Serena is open-source and has a small codebase, so it can be easily extended
  and modified.

## API-Based Coding Agents

An alternative to subscription-based agents are API-based agents like Claude
Code, Cline, Aider, Roo Code and others, where the usage costs map directly
to the API costs of the underlying LLM.
Some of them (like Cline) can even be included in IDEs as an extension.
They are often very powerful and their main downside are the (potentially very
high) API costs.
Serena itself can be used as an API-based agent (see the [section on Agno](../03-special-guides/custom_agent.md)).

The main difference between Serena and other API-based agents is that Serena can
also be used as an MCP server, thus not requiring
an API key and bypassing the API costs.

## Other MCP-Based Coding Agents

There are other MCP servers designed for coding, like [DesktopCommander](https://github.com/wonderwhy-er/DesktopCommanderMCP) and
[codemcp](https://github.com/ezyang/codemcp).
However, to the best of our knowledge, none of them provide semantic code
retrieval and editing tools; they rely purely on text-based analysis.
It is the integration of language servers and the MCP that makes Serena unique
and so powerful for challenging coding tasks, especially in the context of
larger codebases.
```

--------------------------------------------------------------------------------
/src/serena/tools/config_tools.py:
--------------------------------------------------------------------------------

```python
from serena.config.context_mode import SerenaAgentMode
from serena.tools import Tool, ToolMarkerDoesNotRequireActiveProject, ToolMarkerOptional


class ActivateProjectTool(Tool, ToolMarkerDoesNotRequireActiveProject):
    """
    Activates a project based on the project name or path.
    """

    def apply(self, project: str) -> str:
        """
        Activates the project with the given name or path.

        :param project: the name of a registered project to activate or a path to a project directory
        """
        active_project = self.agent.activate_project_from_path_or_name(project)
        return active_project.get_activation_message()


class RemoveProjectTool(Tool, ToolMarkerDoesNotRequireActiveProject, ToolMarkerOptional):
    """
    Removes a project from the Serena configuration.
    """

    def apply(self, project_name: str) -> str:
        """
        Removes a project from the Serena configuration.

        :param project_name: Name of the project to remove
        """
        self.agent.serena_config.remove_project(project_name)
        return f"Successfully removed project '{project_name}' from configuration."


class SwitchModesTool(Tool, ToolMarkerOptional):
    """
    Activates modes by providing a list of their names
    """

    def apply(self, modes: list[str]) -> str:
        """
        Activates the desired modes, like ["editing", "interactive"] or ["planning", "one-shot"]

        :param modes: the names of the modes to activate
        """
        mode_instances = [SerenaAgentMode.load(mode) for mode in modes]
        self.agent.set_modes(mode_instances)

        # Inform the Agent about the activated modes and the currently active tools
        result_str = f"Successfully activated modes: {', '.join([mode.name for mode in mode_instances])}" + "\n"
        result_str += "\n".join([mode_instance.prompt for mode_instance in mode_instances]) + "\n"
        result_str += f"Currently active tools: {', '.join(self.agent.get_active_tool_names())}"
        return result_str


class GetCurrentConfigTool(Tool):
    """
    Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
    """

    def apply(self) -> str:
        """
        Print the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
        """
        return self.agent.get_current_config_overview()

```

--------------------------------------------------------------------------------
/test/resources/repos/ruby/test_repo/examples/user_management.rb:
--------------------------------------------------------------------------------

```ruby
require '../services.rb'
require '../models.rb'

class UserStats
  attr_reader :user_count, :active_users, :last_updated

  def initialize
    @user_count = 0
    @active_users = 0
    @last_updated = Time.now
  end

  def update_stats(total, active)
    @user_count = total
    @active_users = active
    @last_updated = Time.now
  end

  def activity_ratio
    return 0.0 if @user_count == 0
    (@active_users.to_f / @user_count * 100).round(2)
  end

  def formatted_stats
    "Users: #{@user_count}, Active: #{@active_users} (#{activity_ratio}%)"
  end
end

class UserManager
  def initialize
    @service = Services::UserService.new
    @stats = UserStats.new
  end

  def create_user_with_tracking(id, name, email = nil)
    user = @service.create_user(id, name)
    user.email = email if email
    
    update_statistics
    notify_user_created(user)
    
    user
  end

  def get_user_details(id)
    user = @service.get_user(id)
    return nil unless user
    
    {
      user_info: user.full_info,
      created_at: Time.now,
      stats: @stats.formatted_stats
    }
  end

  def bulk_create_users(user_data_list)
    created_users = []
    
    user_data_list.each do |data|
      user = create_user_with_tracking(data[:id], data[:name], data[:email])
      created_users << user
    end
    
    created_users
  end

  private

  def update_statistics
    total_users = @service.users.length
    # For demo purposes, assume all users are active
    @stats.update_stats(total_users, total_users)
  end

  def notify_user_created(user)
    puts "User created: #{user.name} (ID: #{user.id})"
  end
end

def process_user_data(raw_data)
  processed = raw_data.map do |entry|
    {
      id: entry["id"] || entry[:id],
      name: entry["name"] || entry[:name],
      email: entry["email"] || entry[:email]
    }
  end
  
  processed.reject { |entry| entry[:name].nil? || entry[:name].empty? }
end

def main
  # Example usage
  manager = UserManager.new
  
  sample_data = [
    { id: 1, name: "Alice Johnson", email: "[email protected]" },
    { id: 2, name: "Bob Smith", email: "[email protected]" },
    { id: 3, name: "Charlie Brown" }
  ]
  
  users = manager.bulk_create_users(sample_data)
  
  users.each do |user|
    details = manager.get_user_details(user.id)
    puts details[:user_info]
  end
  
  puts "\nFinal statistics:"
  stats = UserStats.new
  stats.update_stats(users.length, users.length)
  puts stats.formatted_stats
end

# Execute if this file is run directly
main if __FILE__ == $0
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
# Base stage with common dependencies
FROM python:3.11-slim AS base
SHELL ["/bin/bash", "-c"]

# Set environment variables to make Python print directly to the terminal and avoid .pyc files.
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

# Install system dependencies required for package manager and build tools.
# sudo, wget, zip needed for some assistants, like junie
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    build-essential \
    git \
    ssh \
    sudo \
    wget \
    zip \
    unzip \
    git \
    && rm -rf /var/lib/apt/lists/*

# Install pipx.
RUN python3 -m pip install --no-cache-dir pipx \
    && pipx ensurepath

# Install nodejs
ENV NVM_VERSION=0.40.3
ENV NODE_VERSION=22.18.0
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash
# standard location
ENV NVM_DIR=/root/.nvm
RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION}
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION}
RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION}
ENV PATH="${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}"

# Add local bin to the path
ENV PATH="${PATH}:/root/.local/bin"

# Install the latest version of uv
RUN curl -LsSf https://astral.sh/uv/install.sh | sh

# Install Rust and rustup for rust-analyzer support (minimal profile)
ENV RUSTUP_HOME=/usr/local/rustup
ENV CARGO_HOME=/usr/local/cargo
ENV PATH="${CARGO_HOME}/bin:${PATH}"
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
    --default-toolchain stable \
    --profile minimal \
    && rustup component add rust-analyzer

# Set the working directory
WORKDIR /workspaces/serena

# Development target
FROM base AS development
# Copy all files for development
COPY . /workspaces/serena/

# Create virtual environment and install dependencies with dev extras
RUN uv venv
RUN . .venv/bin/activate
RUN uv pip install --all-extras -r pyproject.toml -e .
ENV PATH="/workspaces/serena/.venv/bin:${PATH}"

# Entrypoint to ensure environment is activated
ENTRYPOINT ["/bin/bash", "-c", "source .venv/bin/activate && $0 $@"]

# Production target
FROM base AS production
# Copy only necessary files for production
COPY pyproject.toml /workspaces/serena/
COPY README.md /workspaces/serena/
COPY src/ /workspaces/serena/src/

# Create virtual environment and install dependencies (production only)
RUN uv venv
RUN . .venv/bin/activate
RUN uv pip install -r pyproject.toml -e .
ENV PATH="/workspaces/serena/.venv/bin:${PATH}"

# Entrypoint to ensure environment is activated
ENTRYPOINT ["/bin/bash", "-c", "source .venv/bin/activate && $0 $@"]


```

--------------------------------------------------------------------------------
/docs/03-special-guides/custom_agent.md:
--------------------------------------------------------------------------------

```markdown
# Custom Agents with Serena

As a reference implementation, we provide an integration with the [Agno](https://docs.agno.com/introduction/playground) agent framework.
Agno is a model-agnostic agent framework that allows you to turn Serena into an agent 
(independent of the MCP technology) with a large number of underlying LLMs. While Agno has recently
added support for MCP servers out of the box, our Agno integration predates this and is a good illustration of how
easy it is to integrate Serena into an arbitrary agent framework.

Here's how it works:

1. Download the agent-ui code with npx
   ```shell
   npx create-agent-ui@latest
   ```
   or, alternatively, clone it manually:
   ```shell
   git clone https://github.com/agno-agi/agent-ui.git
   cd agent-ui 
   pnpm install 
   pnpm dev
   ```

2. Install serena with the optional requirements:
   ```shell
   # You can also only select agno,google or agno,anthropic instead of all-extras
   uv pip install --all-extras -r pyproject.toml -e .
   ```
   
3. Copy `.env.example` to `.env` and fill in the API keys for the provider(s) you
   intend to use.

4. Start the agno agent app with
   ```shell
   uv run python scripts/agno_agent.py
   ```
   By default, the script uses Claude as the model, but you can choose any model
   supported by Agno (which is essentially any existing model).

5. In a new terminal, start the agno UI with
   ```shell
   cd agent-ui 
   pnpm dev
   ```
   Connect the UI to the agent you started above and start chatting. You will have
   the same tools as in the MCP server version.


Here is a short demo of Serena performing a small analysis task with the newest Gemini model:

https://github.com/user-attachments/assets/ccfcb968-277d-4ca9-af7f-b84578858c62


⚠️ IMPORTANT: In contrast to the MCP server approach, tool execution in the Agno UI does
not ask for the user's permission. The shell tool is particularly critical, as it can perform arbitrary code execution. 
While we have never encountered any issues with
this in our testing with Claude, allowing this may not be entirely safe. 
You may choose to disable certain tools for your setup in your Serena project's
configuration file (`.yml`).


## Other Agent Frameworks

It should be straightforward to incorporate Serena into any
agent framework (like [pydantic-ai](https://ai.pydantic.dev/), [langgraph](https://langchain-ai.github.io/langgraph/tutorials/introduction/) or others).
Typically, you need only to write an adapter for Serena's tools to the tool representation in the framework of your choice, 
as was done by us for Agno with `SerenaAgnoToolkit` (see `/src/serena/agno.py`).


```

--------------------------------------------------------------------------------
/test/solidlsp/python/test_retrieval_with_ignored_dirs.py:
--------------------------------------------------------------------------------

```python
from collections.abc import Generator
from pathlib import Path

import pytest

from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language
from test.conftest import create_ls

# This mark will be applied to all tests in this module
pytestmark = pytest.mark.python


@pytest.fixture(scope="module")
def ls_with_ignored_dirs() -> Generator[SolidLanguageServer, None, None]:
    """Fixture to set up an LS for the python test repo with the 'scripts' directory ignored."""
    ignored_paths = ["scripts", "custom_test"]
    ls = create_ls(ignored_paths=ignored_paths, language=Language.PYTHON)
    ls.start()
    try:
        yield ls
    finally:
        ls.stop()


@pytest.mark.parametrize("ls_with_ignored_dirs", [Language.PYTHON], indirect=True)
def test_symbol_tree_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer):
    """Tests that request_full_symbol_tree ignores the configured directory."""
    root = ls_with_ignored_dirs.request_full_symbol_tree()[0]
    root_children = root["children"]
    children_names = {child["name"] for child in root_children}
    assert children_names == {"test_repo", "examples"}


@pytest.mark.parametrize("ls_with_ignored_dirs", [Language.PYTHON], indirect=True)
def test_find_references_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer):
    """Tests that find_references ignores the configured directory."""
    # Location of Item, which is referenced in scripts
    definition_file = "test_repo/models.py"
    definition_line = 56
    definition_col = 6

    references = ls_with_ignored_dirs.request_references(definition_file, definition_line, definition_col)

    # assert that scripts does not appear in the references
    assert not any("scripts" in ref["relativePath"] for ref in references)


@pytest.mark.parametrize("repo_path", [Language.PYTHON], indirect=True)
def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None:
    """Tests that refs and symbols with glob patterns are ignored."""
    ignored_paths = ["*ipts", "custom_t*"]
    ls = create_ls(ignored_paths=ignored_paths, repo_path=str(repo_path), language=Language.PYTHON)
    ls.start()
    # same as in the above tests
    root = ls.request_full_symbol_tree()[0]
    root_children = root["children"]
    children_names = {child["name"] for child in root_children}
    assert children_names == {"test_repo", "examples"}

    # test that the refs and symbols with glob patterns are ignored
    definition_file = "test_repo/models.py"
    definition_line = 56
    definition_col = 6

    references = ls.request_references(definition_file, definition_line, definition_col)
    assert not any("scripts" in ref["relativePath"] for ref in references)

```

--------------------------------------------------------------------------------
/src/solidlsp/settings.py:
--------------------------------------------------------------------------------

```python
"""
Defines settings for Solid-LSP
"""

import logging
import os
import pathlib
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any

from sensai.util.string import ToStringMixin

if TYPE_CHECKING:
    from solidlsp.ls_config import Language

log = logging.getLogger(__name__)


@dataclass
class SolidLSPSettings:
    solidlsp_dir: str = str(pathlib.Path.home() / ".solidlsp")
    """
    Path to the directory in which to store global Solid-LSP data (which is not project-specific)
    """
    project_data_relative_path: str = ".solidlsp"
    """
    Relative path within each project directory where Solid-LSP can store project-specific data, e.g. cache files.
    For instance, if this is ".solidlsp" and the project is located at "/home/user/myproject",
    then Solid-LSP will store project-specific data in "/home/user/myproject/.solidlsp".
    """
    ls_specific_settings: dict["Language", dict[str, Any]] = field(default_factory=dict)
    """
    Advanced configuration option allowing to configure language server implementation specific options.
    Have a look at the docstring of the constructors of the corresponding LS implementations within solidlsp to see which options are available.
    No documentation on options means no options are available.
    """

    def __post_init__(self) -> None:
        os.makedirs(str(self.solidlsp_dir), exist_ok=True)
        os.makedirs(str(self.ls_resources_dir), exist_ok=True)

    @property
    def ls_resources_dir(self) -> str:
        return os.path.join(str(self.solidlsp_dir), "language_servers", "static")

    class CustomLSSettings(ToStringMixin):
        def __init__(self, settings: dict[str, Any] | None) -> None:
            self.settings = settings or {}

        def get(self, key: str, default_value: Any = None) -> Any:
            """
            Returns the custom setting for the given key or the default value if not set.
            If a custom value is set for the given key, the retrieval is logged.

            :param key: the key
            :param default_value: the default value to use if no custom value is set
            :return: the value
            """
            if key in self.settings:
                value = self.settings[key]
                log.info("Using custom LS setting %s for key '%s'", value, key)
            else:
                value = default_value
            return value

    def get_ls_specific_settings(self, language: "Language") -> CustomLSSettings:
        """
        Get the language server specific settings for the given language.

        :param language: The programming language.
        :return: A dictionary of settings for the language server.
        """
        return self.CustomLSSettings(self.ls_specific_settings.get(language))

```

--------------------------------------------------------------------------------
/docs/01-about/020_programming-languages.md:
--------------------------------------------------------------------------------

```markdown
# Language Support

Serena's semantic code analysis capabilities build on **language servers** using the widely implemented
language server protocol (LSP). The LSP provides a set of versatile code querying
and editing functionalities based on symbolic understanding of the code.
Equipped with these capabilities, Serena discovers and edits code just like a seasoned developer
making use of an IDE's capabilities would.
Serena can efficiently find the right context and do the right thing even in very large and
complex projects! So not only is it free and open-source, it frequently achieves better results
than existing solutions that charge a premium.

Language servers provide support for a wide range of programming languages.
With Serena, we provide direct, out-of-the-box support for:

* **AL**
* **Bash**
* **C#**
* **C/C++**  
  (you may experience issues with finding references, we are working on it)
* **Clojure**
* **Dart**
* **Elixir**  
  (requires installation of NextLS and Elixir; Windows not supported)
* **Elm**  
  (requires Elm compiler)
* **Erlang**  
  (requires installation of beam and [erlang_ls](https://github.com/erlang-ls/erlang_ls); experimental, might be slow or hang)
* **Fortran**  
  (requires installation of fortls: `pip install fortls`)
* **Go**  
  (requires installation of `gopls`)
* **Haskell**  
  (automatically locates HLS via ghcup, stack, or system PATH; supports Stack and Cabal projects)
* **Java**  
* **JavaScript**
* **Julia**
* **Kotlin**  
  (uses the pre-alpha [official kotlin LS](https://github.com/Kotlin/kotlin-lsp), some issues may appear)
* **Lua**
* **Markdown**  
  (must be explicitly specified via `--language markdown` when generating project config, primarily useful for documentation-heavy projects)
* **Nix**  
  (requires nixd installation)
* **Perl**  
  (requires installation of Perl::LanguageServer)
* **PHP**  
  (uses Intelephense LSP; set `INTELEPHENSE_LICENSE_KEY` environment variable for premium features)
* **Python**
* **R**  
  (requires installation of the `languageserver` R package)
* **Ruby**  
  (by default, uses [ruby-lsp](https://github.com/Shopify/ruby-lsp), specify ruby_solargraph as your language to use the previous solargraph based implementation)
* **Rust**  
  (requires [rustup](https://rustup.rs/) - uses rust-analyzer from your toolchain)
* **Scala**  
  (requires some [manual setup](../03-special-guides/scala_setup_guide_for_serena); uses Metals LSP)
* **Swift**
* **TypeScript**
* **Zig**  
  (requires installation of ZLS - Zig Language Server)

Support for further languages can easily be added by providing a shallow adapter for a new language server implementation,
see Serena's [memory on that](https://github.com/oraios/serena/blob/main/.serena/memories/adding_new_language_support_guide.md).

```
Page 1/14FirstPrevNextLast