このドキュメントは、Serenaの全体アーキテクチャを包括的に解説します。システム設計、コンポーネント構成、データフロー、実装パターンなど、Serenaの技術的な側面を網羅的に説明します。
目次
- システム概要
- アーキテクチャ全体像
- レイヤー構造
- 主要コンポーネント詳細
- ツールシステム
- Language Server Protocol統合
- MCPサーバー統合
- データフローと実行フロー
- 設定システム
- メモリシステム
- パフォーマンス最適化
- 開発とカスタマイズ
システム概要
Serenaとは
Serenaは、LLM(大規模言語モデル)をコードベース上で直接動作する高機能エージェントに変換する、オープンソースのコーディングエージェントツールキットです。
コア価値提案:
従来のエージェント:
❌ ファイル全体を読み込む
❌ grepやテキスト置換で操作
❌ 大量のトークンを消費
Serena:
✅ シンボルレベルでピンポイント操作
✅ LSPによる意味解析
✅ トークン効率96%向上
✅ 20以上の言語に対応
主な特徴
- 🚀 IDE相当の機能: IDEのようなセマンティックコード検索・編集機能を提供
- 🔓 LLM・フレームワーク非依存: 特定のLLM、フレームワーク、インターフェースに依存しない
- 🛠️ シンボルレベル操作: コードをシンボルレベルで抽出・編集し、関係構造を活用
- 💰 無料・オープンソース: 完全に無料で利用可能
- 🌐 MCP対応: Model Context Protocol (MCP) サーバーとして動作可能
対応プログラミング言語(20以上)
Python TypeScript/JavaScript PHP (Intelephense)
Go (gopls) Rust (rust-analyzer) C/C++ (clangd)
C# Ruby (ruby-lsp) Swift (sourcekit-lsp)
Kotlin Java (eclipse.jdt.ls) Clojure (clojure-lsp)
Dart Bash Lua (lua-language-server)
Nix (nixd) Elixir (NextLS) Erlang (erlang_ls)
Zig (ZLS) AL (Dynamics 365) R (languageserver)
アーキテクチャ全体像
システム構成図
デュアルレイヤー設計
レイヤー構造
Layer 1: クライアントインターフェース層
責務: LLMクライアントとの通信
機能:
- MCP Protocol / OpenAPI による標準化された通信
- リクエスト/レスポンスのシリアライゼーション
- 認証・セッション管理
対応クライアント:
- Claude Desktop, Claude Code
- Codex, Gemini-CLI, Qwen3-Coder
- VSCode, Cursor, Windsurf
- Cline, Roo Code
- OpenWebUI, Jan, Agno
Layer 2: Serena MCP Server層
責務: リクエストのルーティングとバリデーション
# src/serena/mcp_server.py
class SerenaMCPServer:
"""
MCPリクエストを受け取り、SerenaAgentに委譲
"""
- リクエストのルーティング
- パラメータバリデーション
- タイムアウト制御
- ロギングとダッシュボード機能
通信プロトコル:
- stdio (標準入出力) - デフォルト
- Streamable HTTP - HTTPベースの双方向通信
- SSE - 非推奨
Layer 3: SerenaAgent - コアオーケストレーション層
責務: システム全体の中核となるオーケストレーター
# src/serena/agent.py
class SerenaAgent:
"""
プロジェクト管理、ツール実行、状態管理を統括
"""
- プロジェクトのアクティベーションと管理
- ツールレジストリとディスパッチ
- コンテキスト・モード管理
- メモリ管理
- 言語サーバーのライフサイクル管理
主要メソッド:
def activate_project(self, project_identifier) -> str
def execute_task(self, task_callable) -> T
def get_tool(self, tool_class) -> Tool
def switch_modes(self, mode_names) -> None
def get_available_tools(self) -> AvailableTools
Layer 4: Tool実行層
責務: 各種操作の実装
ツールカテゴリ:
├── シンボルツール (symbol_tools.py)
│ - find_symbol, find_referencing_symbols
│ - get_symbols_overview
│ - replace_symbol_body
│
├── ファイルツール (file_tools.py)
│ - read_file, write_file
│ - search_for_pattern, replace_regex
│
├── コマンドツール (cmd_tools.py)
│ - execute_shell_command
│
├── メモリツール (memory_tools.py)
│ - write_memory, read_memory, list_memories
│
├── 設定ツール (config_tools.py)
│ - activate_project, switch_modes
│
└── ワークフローツール (workflow_tools.py)
- onboarding, prepare_for_new_conversation
Layer 5: SolidLSP層(言語サーバー抽象化)
責備: 言語サーバーとの通信とキャッシング
# src/solidlsp/ls.py
class SolidLanguageServer(ABC):
"""
複数言語サーバーの統一インターフェース
"""
- 言語サーバーとの通信
- シンボル情報のキャッシング
- ドキュメント同期管理
- エラーハンドリングと自動リトライ
主要メソッド:
def request_document_symbols(self, relative_path, include_body) -> tuple
def request_definition(self, relative_path, line, character) -> list
def request_references(self, relative_path, line, character) -> list
def start_server(self) -> ContextManager
def save_cache(self) -> None
Layer 6: 言語サーバープロセス層
責務: 各言語専用の言語サーバー実行
言語サーバー階層:
SolidLanguageServer (Abstract Base)
├── PythonLanguageServer (Pyright)
├── TypeScriptLanguageServer (typescript-language-server)
├── RustLanguageServer (rust-analyzer)
├── GoLanguageServer (gopls)
├── JavaLanguageServer (eclipse.jdt.ls)
├── PHPLanguageServer (Intelephense)
└── ... (他16言語)
主要コンポーネント詳細
1. SerenaAgent (src/serena/agent.py)
役割: システム全体の中核となるオーケストレーター
ライフサイクル:
状態管理:
class SerenaAgent:
_active_project: Project | None
_active_project_lock: threading.Lock
_active_ls: SolidLanguageServer | None
_memories_manager: MemoriesManager | None
_tool_registry: dict[str, Tool]
_context: Context
_modes: list[Mode]
2. SolidLanguageServer (src/solidlsp/ls.py)
役割: 言語サーバープロトコル(LSP)の統一インターフェース
キャッシング戦略:
self._document_symbols_cache: dict[
str, # ファイルパス
tuple[
str, # ファイルハッシュ (MD5)
tuple[
list[UnifiedSymbolInformation], # シンボル情報
list[UnifiedSymbolInformation] # ボディ含むシンボル情報
]
]
]
キャッシュフロー:
キャッシュの無効化条件:
- ファイル内容変更時(ハッシュ変更)
- 明示的なキャッシュクリア
- 言語サーバーバージョン変更時
3. Project Management (src/serena/project.py)
役割: プロジェクト固有の設定と操作の管理
プロジェクト構成:
project_root/
├── .serena/
│ ├── project.yml # プロジェクト設定
│ ├── cache/ # 言語サーバーキャッシュ
│ │ └── PythonLanguageServer.pkl
│ ├── memories/ # メモリファイル(Markdown)
│ │ ├── architecture.md
│ │ ├── how_to_test.md
│ │ └── how_to_build.md
│ └── logs/ # ログファイル
├── src/ # ソースコード
└── ...
主要機能:
class Project:
def gather_source_files(self) -> list[str]
"""gitignoreを尊重してソースファイルを収集"""
def is_ignored_path(self, path) -> bool
"""パスが無視対象かどうか判定"""
def create_language_server(self) -> SolidLanguageServer
"""プロジェクトの言語に応じたLSを作成"""
def search_text_in_project(self, pattern, ...) -> dict
"""正規表現でプロジェクト全体を検索"""
4. Memory System (agent.py: MemoriesManager)
役割: プロジェクト知識の永続化と取得
メモリの種類:
.serena/memories/
├── project_structure.md # プロジェクト構造
├── how_to_test.md # テスト実行方法
├── how_to_build.md # ビルド手順
├── architecture.md # アーキテクチャ概要
├── key_symbols.md # 重要なシンボル
├── coding_conventions.md # コーディング規約
└── task_progress.md # タスク進捗(継続作業用)
メモリライフサイクル:
1. オンボーディング時に自動作成
└─ プロジェクト構造、テスト方法等を分析
2. 作業中に手動/自動で追加
└─ 設計決定、規約、進捗状況等
3. 新セッション開始時に読み込み
└─ list_memories → read_memory
4. 必要に応じて更新・削除
└─ 情報が古くなった場合
5. Tool System (src/serena/tools/)
ツールベースクラス階層:
Tool (Component)
├─ ToolMarkerSymbolicRead # シンボル読み取り系
├─ ToolMarkerCanEdit # 編集系
├─ ToolMarkerOptional # オプショナル(デフォルト無効)
└─ ToolMarkerDoesNotRequireActiveProject # プロジェクト不要
ツール実装パターン:
class MyTool(Tool, ToolMarkerCanEdit):
"""
ツールの説明。LLMが読む。
"""
def apply(
self,
param1: str,
param2: int = 10,
max_answer_chars: int = -1
) -> str:
"""
詳細な説明。
:param param1: パラメータ1
:param param2: パラメータ2
:param max_answer_chars: 出力文字数制限
:return: 実行結果
"""
# 1. パラメータ検証
# 2. プロジェクトルート取得
project_root = self.get_project_root()
# 3. 実際の処理
result = perform_operation(param1, param2)
# 4. 文字数制限適用
return self._limit_length(result, max_answer_chars)
ツール実行フロー:
ツールシステム
デフォルト有効ツール(27個)
シンボルツール
# find_symbol: グローバル/ローカルシンボル検索
find_symbol(
name_path="/MyClass/myMethod", # シンボルパス
depth=1, # 子要素の深さ
include_body=True, # ボディを含む
include_kinds=[5, 6] # クラス、メソッドのみ
)
# find_referencing_symbols: シンボル参照検索
find_referencing_symbols(
name_path="/authenticate",
relative_path="src/auth.py"
)
# get_symbols_overview: ファイル内シンボル一覧
get_symbols_overview(relative_path="src/main.py")
# replace_symbol_body: シンボル定義の置換
replace_symbol_body(
name_path="/MyClass/foo",
relative_path="src/main.py",
new_body="def foo(self):\n pass"
)
# insert_after_symbol: シンボル後に挿入
insert_after_symbol(
name_path="/MyClass",
relative_path="src/main.py",
content=" def new_method(self):\n pass"
)
# insert_before_symbol: シンボル前に挿入
insert_before_symbol(
name_path="/MyClass",
relative_path="src/main.py",
content="# Important class\n"
)
シンボルカインド(LSP標準):
1=file, 2=module, 3=namespace, 4=package, 5=class, 6=method,
7=property, 8=field, 9=constructor, 10=enum, 11=interface,
12=function, 13=variable, 14=constant, 15=string, 16=number,
17=boolean, 18=array, 19=object, 20=key, 21=null,
22=enum member, 23=struct, 24=event, 25=operator, 26=type parameter
名前パスマッチング:
"method" → method, class/method, class/nested/method
"class/method" → class/method, nested/class/method (但しmethodは単独NG)
"/class/method" → class/method のみ(絶対パス)
ファイルツール
# read_file: ファイル読み取り
read_file(relative_path="src/main.py", max_lines=100)
# create_text_file: ファイル作成・上書き
create_text_file(
relative_path="src/new.py",
content="def hello():\n print('Hello')"
)
# search_for_pattern: 正規表現パターン検索
search_for_pattern(
pattern=r"def\s+\w+",
include_glob="**/*.py",
context_lines=2
)
# replace_regex: 正規表現置換
replace_regex(
relative_path="src/main.py",
pattern=r"old_name",
replacement="new_name"
)
# list_dir: ディレクトリ一覧
list_dir(relative_path="src/", recursive=True)
# find_file: ファイル検索
find_file(
pattern="**/test_*.py",
relative_path="tests/"
)
メモリツール
# write_memory: メモリ保存
write_memory(
memory_name="api_conventions.md",
content="# API設計原則\n..."
)
# read_memory: メモリ読み取り
read_memory(memory_file_name="api_conventions.md")
# list_memories: メモリ一覧
list_memories() # → ["architecture.md", "how_to_test.md", ...]
# delete_memory: メモリ削除
delete_memory(memory_file_name="outdated_info.md")
ワークフローツール
# onboarding: プロジェクトオンボーディング
onboarding() # 自動でプロジェクトを分析してメモリ作成
# check_onboarding_performed: オンボーディング状態確認
check_onboarding_performed()
# prepare_for_new_conversation: 新規会話準備
prepare_for_new_conversation() # 進捗サマリーを生成
# 思考ツール(LLMの自己反省用)
think_about_task_adherence()
think_about_collected_information()
think_about_whether_you_are_done()
設定ツール
# activate_project: プロジェクトアクティベーション
activate_project(project_identifier="/path/to/project")
# switch_modes: モード切り替え
switch_modes(mode_names=["planning", "one-shot"])
コマンドツール
# execute_shell_command: シェルコマンド実行
execute_shell_command(
command="pytest tests/",
working_dir=".",
timeout=60
)
オプションツール(9個)
デフォルトでは無効、明示的に有効化が必要:
# delete_lines: 行削除
# insert_at_line: 行位置に挿入
# replace_lines: 行範囲置換
# get_current_config: 現在の設定表示
# initial_instructions: 初期指示取得
# remove_project: プロジェクト削除
# restart_language_server: 言語サーバー再起動
# jet_brains_find_symbol: JetBrainsシンボル検索
# jet_brains_find_referencing_symbols: JetBrains参照検索
# jet_brains_get_symbols_overview: JetBrainsシンボル一覧
ツールの有効化/無効化制御
# context.yml または mode.yml
included_optional_tools:
- delete_lines
- insert_at_line
excluded_tools:
- execute_shell_command
優先順位:
Language Server Protocol統合
LSPの活用
Language Server Protocol (LSP) は、IDE機能を言語非依存で提供する標準プロトコルです。Serenaは、LSPを通じてセマンティックなコード理解を実現します。
主要なLSP機能:
textDocument/documentSymbol - ファイル内のシンボル一覧取得
textDocument/definition - シンボル定義へのジャンプ
textDocument/references - シンボル参照検索
textDocument/hover - シンボル情報表示
textDocument/didOpen - ドキュメントを開く通知
textDocument/didChange - ドキュメント変更通知
textDocument/didClose - ドキュメントを閉じる通知
SolidLSPレイヤーの設計目標
✅ 非同期LSP通信を同期APIでラップ
✅ 複数言語サーバーの統一インターフェース
✅ 高速化のための積極的なキャッシング
✅ エラーハンドリングと自動リトライ
✅ 言語サーバーのライフサイクル管理
言語サーバーのライフサイクル
エラーハンドリング
一般的なエラーと対処:
# 1. 言語サーバークラッシュ
try:
result = ls.request_document_symbols(path)
except LSPError:
# 自動再起動
# キャッシュからのフォールバック
# 2. タイムアウト
try:
result = ls.request_references(path, pos, timeout=30)
except TimeoutError:
# 部分的な結果の返却
# 3. シンボル見つからず
result = ls.find_symbol(name)
if not result:
# 空のリスト返却
# ログに記録
# 4. ファイルエンコーディングエラー
try:
content = read_file(path, encoding='utf-8')
except UnicodeDecodeError:
# 他のエンコーディングで試行
content = read_file(path, encoding='latin-1')
言語サーバー抽象化
# src/solidlsp/language_servers/
class PythonLanguageServer(SolidLanguageServer):
"""Pyright言語サーバーのラッパー"""
@staticmethod
def get_launch_info(repository_root_path, settings):
return ProcessLaunchInfo(
command="pyright-langserver",
args=["--stdio"],
env={}
)
def is_ignored_dirname(self, dirname: str) -> bool:
return dirname in [
"__pycache__", ".pytest_cache",
"venv", ".venv", "env"
]
class TypeScriptLanguageServer(SolidLanguageServer):
"""TypeScript言語サーバーのラッパー"""
@staticmethod
def get_launch_info(repository_root_path, settings):
return ProcessLaunchInfo(
command="typescript-language-server",
args=["--stdio"],
env={}
)
def is_ignored_dirname(self, dirname: str) -> bool:
return dirname in ["node_modules", "dist", "build"]
MCPサーバー統合
Model Context Protocol (MCP) とは
MCPは、LLMクライアントが外部ツールやデータソースと対話するための標準プロトコルです。Anthropic社が策定し、Claude Desktop等で採用されています。
MCPの主要概念:
Server - ツールやリソースを提供するサービス
Client - ツールを呼び出すLLMアプリケーション
Tool - 実行可能な関数
Resource - 読み取り可能なデータ
Prompt - 事前定義されたプロンプトテンプレート
Serena MCP Serverアーキテクチャ
MCPツール変換
SerenaのToolからMCPツールへの変換:
def make_mcp_tool(serena_tool: Tool) -> MCPTool:
"""
1. apply()メソッドのシグネチャを抽出
2. 型アノテーションをJSON Schemaに変換
3. docstringをツール説明に変換
4. Pydanticモデルを生成してバリデーション設定
"""
変換例:
# Serena Tool
class FindSymbolTool(Tool):
def apply(
self,
name_path: str,
depth: int = 0,
include_body: bool = False
) -> str:
"""
シンボルを検索します。
:param name_path: 検索するシンボル名
:param depth: 取得する階層の深さ
:param include_body: ボディを含むか
:return: JSON形式の検索結果
"""
# 変換後のMCP Tool
{
"name": "find_symbol",
"description": "シンボルを検索します。",
"inputSchema": {
"type": "object",
"properties": {
"name_path": {
"type": "string",
"description": "検索するシンボル名"
},
"depth": {
"type": "integer",
"default": 0,
"description": "取得する階層の深さ"
},
"include_body": {
"type": "boolean",
"default": false,
"description": "ボディを含むか"
}
},
"required": ["name_path"]
}
}
通信プロトコル
Serenaがサポートする3つのトランスポート:
1. stdio (標準入出力)
// Claude Desktop設定例
{
"mcpServers": {
"serena": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/oraios/serena",
"serena", "start-mcp-server"
]
}
}
}
- デフォルト
- クライアントがサーバーをサブプロセスとして起動
- Claude Desktop、Claude Code等で使用
2. Streamable HTTP
# サーバー起動
serena start-mcp-server --transport streamable-http --port 9121
# クライアント接続先
http://localhost:9121/mcp
- HTTPベースの双方向通信
- サーバーを独立して起動
- 複数クライアントから接続可能
3. SSE (Server-Sent Events)
# 非推奨(Streamable HTTPを推奨)
serena start-mcp-server --transport sse --port 9122
データフローと実行フロー
典型的な実行フロー: "クラスFooのメソッドbarを見つけて編集"
プロジェクトアクティベーションフロー
オンボーディングフロー
設定システム
設定ファイルの階層と優先順位
serena_config.yml
場所: ~/.serena/serena_config.yml
# ログ設定
log_level: INFO # DEBUG, INFO, WARNING, ERROR, CRITICAL
# ダッシュボード設定
web_dashboard: true
web_dashboard_open_on_launch: true
gui_log_window_enabled: false
# ツール実行設定
tool_timeout: 300.0 # 秒
max_answer_chars: 30000
# 言語サーバー設定
trace_lsp_communication: false
ls_specific_settings:
python:
pyrightconfig:
analysis:
typeCheckingMode: "basic"
typescript:
preferences:
includeInlayParameterNameHints: "all"
# 統計記録
record_tool_usage_stats: true
token_count_estimator: cl100k_base # tiktoken encoding
# 登録済みプロジェクト
projects:
- name: my_project
path: /absolute/path/to/project
language: python
project.yml
場所: <project_root>/.serena/project.yml
# プロジェクト識別
project_name: my_awesome_project
# 言語設定
language: python # または auto
# エンコーディング
encoding: utf-8
# 読み取り専用モード
read_only: false
# 無視パス
ignored_paths:
- "**/__pycache__/**"
- "**/node_modules/**"
- "**/.git/**"
# .gitignoreを尊重するか
ignore_all_files_in_gitignore: true
# ツール除外
excluded_tools:
- execute_shell_command
# ツール包含(オプションツール)
included_optional_tools:
- delete_lines
Context & Mode システム
コンテキスト (Context)
定義: Serenaが動作する環境の定義
組み込みコンテキスト:
# 1. desktop-app (デフォルト)
name: desktop-app
description: Claude Desktop等のデスクトップアプリ用
included_optional_tools:
- execute_shell_command
excluded_tools: []
# 2. agent
name: agent
description: 自律エージェント用(Agno等)
# フル機能セット
# 3. ide-assistant
name: ide-assistant
description: IDE統合用(Cursor、Cline等)
excluded_tools:
- execute_shell_command # IDE既存機能との重複を避ける
# 4. codex
name: codex
description: OpenAI Codex CLI用
# MCP仕様の非互換性を吸収
# 5. oaicompat-agent
name: oaicompat-agent
description: OpenAI互換ローカルサーバー用
openai_tool_compatible: true
モード (Mode)
定義: 特定のタスクタイプや対話スタイルへの最適化
組み込みモード:
# 1. planning: 計画・分析重視
name: planning
description: 実装前の設計フェーズ
excluded_tools:
- replace_symbol_body
- create_text_file
# 2. editing: コード編集重視
name: editing
description: 実装フェーズ
# 編集ツール優先
# 3. interactive: 対話型
name: interactive
description: ユーザーとの頻繁なやり取り
# 4. one-shot: 一発完了型
name: one-shot
description: 一度の応答で完了
# 5. no-onboarding: オンボーディングスキップ
name: no-onboarding
description: 既知プロジェクト用
# 6. onboarding: オンボーディング専用
name: onboarding
description: 自動トリガー
モード切り替え:
# 実行時に動的に切り替え可能
switch_modes(mode_names=["planning", "one-shot"])
カスタムコンテキスト・モードの作成
# コンテキスト作成
serena context create --name my_context
serena context edit my_context
# モード作成
serena mode create --name my_mode
serena mode edit my_mode
# 使用
serena start-mcp-server \
--context my_context \
--mode my_mode
カスタム設定例:
# ~/.serena/contexts/my_context.yml
name: my_custom_context
description: 私のカスタムコンテキスト
prompt: |
You are Serena, an AI coding assistant.
{{project_specific_instructions}}
Available tools: {{tool_names}}
included_optional_tools:
- initial_instructions
excluded_tools:
- execute_shell_command
openai_tool_compatible: false
メモリシステム
メモリの仕組み
保存場所: <project_root>/.serena/memories/
形式: Markdown(人間にも読みやすい)
特徴:
- プロジェクト固有の知識を永続化
- セッションをまたいで利用可能
- 手動編集が可能
- LLMが自動的に読み書き
メモリの種類
.serena/memories/
├── project_structure.md # プロジェクト構造
│ - ディレクトリ構成
│ - 主要ファイルの説明
│ - モジュール間の関係
│
├── how_to_test.md # テスト実行方法
│ - テストフレームワーク
│ - テストコマンド
│ - CI/CD設定
│
├── how_to_build.md # ビルド手順
│ - ビルドツール
│ - ビルドコマンド
│ - 環境設定
│
├── architecture.md # アーキテクチャ概要
│ - システム設計
│ - デザインパターン
│ - データフロー
│
├── key_symbols.md # 重要なシンボル
│ - 主要クラス・関数
│ - エントリーポイント
│ - ユーティリティ
│
├── coding_conventions.md # コーディング規約
│ - 命名規則
│ - ディレクトリ構造規約
│ - コメント規約
│
└── task_progress.md # タスク進捗(継続作業用)
- 現在の状態
- 完了した作業
- 次にやるべきこと
メモリの活用例
# .serena/memories/api_conventions.md
## API設計原則
このプロジェクトでは以下の原則に従ってAPIを設計:
1. RESTful な URL 構造
2. すべてのエンドポイントは `/api/v1/` プレフィックス
3. 認証は JWT トークンを使用
4. エラーレスポンスは RFC 7807 形式
## 新規エンドポイント追加手順
1. `src/api/routes/` に新しいルートファイルを作成
2. `src/api/__init__.py` にルートを登録
3. `test/api/` にテストを追加
4. ドキュメントを `docs/api/` に追加
## 既存のエンドポイント
- `/api/v1/users` - ユーザー管理
- GET /users - ユーザー一覧
- POST /users - ユーザー作成
- GET /users/{id} - ユーザー詳細
- `/api/v1/auth` - 認証・認可
- POST /auth/login - ログイン
- POST /auth/refresh - トークン更新
- `/api/v1/products` - 商品管理
- GET /products - 商品一覧
- POST /products - 商品作成
## エラーハンドリング
すべてのエンドポイントは以下の形式でエラーを返す:
```json
{
"type": "https://example.com/errors/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "The requested user was not found",
"instance": "/api/v1/users/123"
}
### メモリライフサイクル
```mermaid
graph TD
A[メモリライフサイクル]
A --> B[1.オンボーディング時]
B --> C[onboarding ツール実行]
C --> D[自動でメモリ作成<br/>project_structure.md<br/>how_to_test.md等]
A --> E[2.作業中]
E --> F[write_memory で手動作成<br/>設計決定、規約、メモ等]
E --> G[prepare_for_new_conversation<br/>で進捗保存<br/>task_progress.md]
A --> H[3.新セッション開始時]
H --> I[list_memories で一覧取得]
I --> J[read_memory で読み込み]
A --> K[4.更新・削除]
K --> L[write_memory で上書き<br/>更新]
K --> M[delete_memory で削除]
style B fill:#e1f5ff
style E fill:#fff4e1
style H fill:#e1ffe1
style K fill:#ffe1f5
コンテキスト枯渇時の継続性
長いタスクでコンテキストが一杯になった場合:
1. prepare_for_new_conversation ツールを実行
→ 現在の進捗状況をサマリ化
2. write_memory で "task_progress.md" に保存
内容:
- 完了した作業
- 現在の状態
- 次にやるべきこと
- 重要な決定事項
3. 新しいセッションを開始
4. read_memory("task_progress.md") で前回の状態を復元
5. 作業を継続
パフォーマンス最適化
キャッシング戦略
シンボル情報のキャッシュ
# src/solidlsp/ls.py
self._document_symbols_cache: dict[
str, # ファイルパス
tuple[
str, # ファイルハッシュ (MD5)
tuple[...] # シンボル情報
]
]
キャッシュの動作:
キャッシュファイル:
<project_root>/.serena/cache/
├── PythonLanguageServer.pkl
├── TypeScriptLanguageServer.pkl
└── ...
パフォーマンス指標
典型的な実行時間 (中規模Pythonプロジェクト、10,000行):
| 操作 | 初回(キャッシュなし) | 2回目以降(キャッシュあり) |
|---|---|---|
| プロジェクトアクティベーション | 5-10秒 | 1-2秒 |
| シンボル検索(単一ファイル) | 500ms-1秒 | 50-100ms |
| シンボル検索(プロジェクト全体) | 3-5秒 | 200-500ms |
| 参照検索 | 1-3秒 | 500ms-1秒 |
| ファイル読み取り | 10-50ms | 10-50ms |
| シンボル編集 | 100-300ms | 100-300ms |
メモリ使用量:
Serena本体: 50-100MB
言語サーバー: 100-500MB(言語による)
キャッシュ: 1-50MB(プロジェクトサイズによる)
プロジェクトインデックス
# 事前にシンボル情報をキャッシュ
serena project index /path/to/project
# 特定ファイルだけインデックス
serena project index-file src/main.py /path/to/project
# 詳細表示
serena project index-file src/main.py --verbose
設定での最適化
# serena_config.yml
# タイムアウト調整
tool_timeout: 600.0 # 大規模プロジェクト用
# 言語サーバー固有設定
ls_specific_settings:
python:
analysis:
useLibraryCodeForTypes: false # 高速化
diagnosticMode: "openFilesOnly"
typescript:
preferences:
disableSuggestions: true # 不要な機能を無効化
開発とカスタマイズ
開発環境のセットアップ
# リポジトリクローン
git clone https://github.com/oraios/serena
cd serena
# 依存関係インストール(開発用)
uv sync --all-extras
# 設定ファイル生成
uv run serena config edit
# テスト実行
uv run poe test
# コードフォーマット
uv run poe format
# 型チェック
uv run poe type-check
# リント
uv run poe lint
新しいツールの追加
ステップ:
# 1. ツールクラス作成 (src/serena/tools/my_tools.py)
from serena.tools import Tool, ToolMarkerOptional
class MyCustomTool(Tool, ToolMarkerOptional):
"""
カスタムツールの説明。
"""
def apply(self, param1: str, param2: int = 10) -> str:
"""
詳細な説明。
:param param1: パラメータ1
:param param2: パラメータ2
:return: 実行結果
"""
# 実装
result = f"Processed {param1} with {param2}"
return result
# 2. ツールを__init__.pyに追加
# src/serena/tools/__init__.py
from .my_tools import *
# 3. テスト作成 (test/serena/test_my_tools.py)
def test_my_custom_tool(serena_agent):
tool = serena_agent.get_tool(MyCustomTool)
result = tool.apply("test", 20)
assert "test" in result
assert "20" in result
# 4. ツールを有効化(オプションツールの場合)
# context.yml or mode.yml
included_optional_tools:
- my_custom_tool
新しい言語サーバーの追加
# 1. 言語サーバークラス作成
# src/solidlsp/language_servers/my_language_server.py
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
class MyLanguageServer(SolidLanguageServer):
@staticmethod
def get_launch_info(
repository_root_path: str,
solidlsp_settings
) -> ProcessLaunchInfo:
"""言語サーバーの起動情報を返す"""
return ProcessLaunchInfo(
command="my-language-server",
args=["--stdio"],
env={}
)
def is_ignored_dirname(self, dirname: str) -> bool:
"""無視すべきディレクトリ"""
if super().is_ignored_dirname(dirname):
return True
return dirname in ["build", "dist"]
# 2. 言語列挙に追加 (src/solidlsp/ls_config.py)
class Language(Enum):
MY_LANGUAGE = "my_language"
# 3. ファクトリメソッドに追加 (src/solidlsp/ls.py)
def create(...):
elif language == Language.MY_LANGUAGE:
from solidlsp.language_servers.my_language_server import MyLanguageServer
ls = MyLanguageServer(...)
# 4. テストリポジトリ作成
# test/resources/repos/mylang/
# 5. テスト作成
# test/solidlsp/mylang/
# 6. pytest マーカー追加 (pyproject.toml)
[tool.pytest.ini_options]
markers = [
"mylang: language server running for MyLang",
]
まとめ
アーキテクチャの利点
✅ 階層化された設計
└─ 各レイヤーが明確な責任を持つ
✅ キャッシング戦略
└─ 高速な応答時間(50-100ms)
✅ エラーハンドリング
└─ 堅牢な実行環境
✅ 拡張性
└─ 新しいツール・言語の追加が容易
✅ LLM・フレームワーク非依存
└─ どんな環境でも利用可能
✅ オープンソース
└─ 完全無料、カスタマイズ自由
主要な強み
1. セマンティックコード理解
└─ シンボルレベルでのコード操作
2. トークン効率
└─ 必要な部分だけを読み取り、コスト削減
3. 20+言語対応
└─ 幅広いプロジェクトで使用可能
4. 柔軟な統合
└─ MCP、OpenAPI、ライブラリとして利用可能
5. メモリシステム
└─ プロジェクト知識の永続化
6. Context & Mode
└─ 用途に応じた最適な動作
推奨ユースケース
✅ 大規模コードベースの探索
└─ シンボルベース検索で効率的
✅ 精密なコード編集
└─ インデント保持、シンボル単位の操作
✅ プロジェクトオンボーディング
└─ 自動的な理解とドキュメント化
✅ コスト削減
└─ トークン効率の向上により API コスト削減
✅ 長期的なプロジェクト作業
└─ メモリシステムで文脈を保持
参考資料
公式ドキュメント
- README.md - プロジェクト概要と使い方
- lessons_learned.md - 開発から学んだ教訓
- CONTRIBUTING.md - 貢献ガイドライン
ソースコード
- src/serena/ - Serenaエージェント実装
- src/solidlsp/ - 言語サーバー統合層
- src/serena/tools/ - ツール実装
- test/ - テストコード
関連プロジェクト
- vscode-languageserver-node - LSPライブラリ
- multilspy - SerenaのベースとなったLSPライブラリ
- Model Context Protocol - MCPプロトコル仕様