diff --git a/src/godotiq/tools/memory/__init__.py b/src/godotiq/tools/memory/__init__.py
index 777a4b7..0223041 100644
--- a/src/godotiq/tools/memory/__init__.py
+++ b/src/godotiq/tools/memory/__init__.py
@@ -1 +1,192 @@
-"""Project Memory tools — session context, decision log."""
+"""Project Memory tools — project summary and file context.
+
+These tools help AI agents understand and navigate a Godot project.
+"""
+
+from __future__ import annotations
+
+from collections import Counter
+
+from mcp.server.fastmcp import Context
+
+from godotiq.server import mcp
+from godotiq.session import GodotIQSession
+
+
+def _read_main_scene(session: GodotIQSession) -> str:
+    """Read run/main_scene from project.godot."""
+    godot_file = session.project_root / "project.godot"
+    if not godot_file.exists():
+        return ""
+    in_application = False
+    for line in godot_file.read_text(encoding="utf-8").splitlines():
+        line = line.strip()
+        if line.startswith("[") and line.endswith("]"):
+            in_application = line == "[application]"
+            continue
+        if in_application and line.startswith("run/main_scene="):
+            value = line.split("=", 1)[1].strip().strip('"')
+            return value
+    return ""
+
+
+def _build_brief(session: GodotIQSession) -> dict:
+    """Build brief-level project summary."""
+    idx = session._index
+    return {
+        "project_name": idx.project_name,
+        "engine": session.config.project.get("engine", "godot_4"),
+        "type": session.config.project.get("type", "unknown"),
+        "counts": {
+            "scenes": idx.total_scenes,
+            "scripts": idx.total_scripts,
+            "assets": idx.total_assets,
+        },
+        "autoloads": list(idx.autoloads.keys()),
+    }
+
+
+def _build_normal(session: GodotIQSession) -> dict:
+    """Build normal-level additions (architecture + scene_structure)."""
+    idx = session._index
+
+    # Architecture block
+    main_scene = _read_main_scene(session)
+    architecture = {
+        "main_scene": main_scene,
+        "autoload_details": dict(idx.autoloads),
+        "scene_tree": list(idx.scenes.keys()),
+        "key_systems": list(idx.autoloads.keys()),
+    }
+
+    # Scene structure block
+    scene_structure: dict[str, dict] = {}
+    for res_path, scene in idx.scenes.items():
+        scene_structure[res_path] = {
+            "root_type": scene.root.type if scene.root else "",
+            "total_nodes": len(scene.nodes),
+            "instances": scene.get_all_instances(),
+            "scripts": scene.get_all_scripts(),
+        }
+
+    return {
+        "architecture": architecture,
+        "scene_structure": scene_structure,
+    }
+
+
+def _build_full(session: GodotIQSession) -> dict:
+    """Build full-level additions (autoload_analysis, file_tree, detected_patterns)."""
+    idx = session._index
+
+    # Autoload analysis
+    autoload_analysis: dict[str, dict] = {}
+    for name, script_path in idx.autoloads.items():
+        gd = session.get_script(script_path)
+        if gd is None:
+            autoload_analysis[name] = {
+                "script_path": script_path,
+                "class_name": "",
+                "extends": "",
+                "signals": [],
+                "public_functions": [],
+                "referenced_by": session.get_autoload_dependents(name),
+            }
+            continue
+        public_funcs = [
+            {"name": f.name, "args": len(f.args), "return_type": f.return_type}
+            for f in gd.functions
+            if not f.is_private
+        ]
+        autoload_analysis[name] = {
+            "script_path": script_path,
+            "class_name": gd.class_name,
+            "extends": gd.extends,
+            "signals": [s.name for s in gd.signals],
+            "public_functions": public_funcs,
+            "referenced_by": session.get_autoload_dependents(name),
+        }
+
+    # File tree
+    asset_types: Counter[str] = Counter()
+    for _path, info in idx.assets.items():
+        asset_types[info.get("type", "resource")] += 1
+
+    file_tree = {
+        "scenes": list(idx.scenes.keys()),
+        "scripts": list(idx.scripts),
+        "assets_by_type": dict(asset_types),
+    }
+
+    # Detected patterns
+    has_serialize = False
+    uses_signals = False
+    uses_groups = False
+    for gd in session._gd_scripts.values():
+        if any(f.name in ("serialize", "deserialize") for f in gd.functions):
+            has_serialize = True
+        if gd.signals:
+            uses_signals = True
+    for scene in idx.scenes.values():
+        for node in scene.nodes:
+            if node.groups:
+                uses_groups = True
+                break
+
+    detected_patterns = {
+        "has_serialize": has_serialize,
+        "uses_signals": uses_signals,
+        "uses_autoloads": bool(idx.autoloads),
+        "uses_groups": uses_groups,
+    }
+
+    return {
+        "autoload_analysis": autoload_analysis,
+        "file_tree": file_tree,
+        "detected_patterns": detected_patterns,
+    }
+
+
+def _build_project_summary(session: GodotIQSession, detail: str = "normal") -> dict:
+    """Build project summary at the requested detail level.
+
+    Args:
+        session: Loaded GodotIQSession.
+        detail: One of "brief", "normal", "full".
+
+    Returns:
+        Dictionary with project summary data.
+    """
+    result = _build_brief(session)
+
+    if detail in ("normal", "full"):
+        result.update(_build_normal(session))
+
+    if detail == "full":
+        result.update(_build_full(session))
+
+    return result
+
+
+@mcp.tool(
+    name="godotiq_project_summary",
+    annotations={
+        "readOnlyHint": True,
+        "destructiveHint": False,
+        "idempotentHint": True,
+        "openWorldHint": False,
+    },
+)
+async def godotiq_project_summary(
+    detail: str = "normal",
+    ctx: Context = None,
+) -> dict:
+    """Complete project overview for AI agent context recovery.
+
+    Args:
+        detail: Level of detail - "brief", "normal", or "full".
+    """
+    session = ctx.request_context.lifespan_context["session"]
+    if session is None:
+        return {"error": "No Godot project loaded. Set GODOTIQ_PROJECT_ROOT or run from project directory."}
+    return _build_project_summary(session, detail)
diff --git a/tests/test_tools/test_project_summary.py b/tests/test_tools/test_project_summary.py
new file mode 100644
index 0000000..e31d18c
--- /dev/null
+++ b/tests/test_tools/test_project_summary.py
@@ -0,0 +1,165 @@
+"""Tests for godotiq_project_summary tool."""
+
+from __future__ import annotations
+
+import pytest
+
+from godotiq.session import GodotIQSession
+
+
+class TestProjectSummaryBrief:
+    def test_summary_brief_has_project_name(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "brief")
+        assert result["project_name"] == "Sample Project"
+
+    def test_summary_brief_has_counts(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "brief")
+        assert "counts" in result
+        assert result["counts"]["scenes"] >= 2
+        assert result["counts"]["scripts"] >= 4
+
+    def test_summary_brief_has_autoloads(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "brief")
+        assert "autoloads" in result
+        assert "GameManager" in result["autoloads"]
+        assert "EconomyManager" in result["autoloads"]
+
+    def test_summary_brief_has_engine(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "brief")
+        assert "engine" in result
+        assert result["engine"] == "godot_4"
+
+    def test_summary_brief_has_type(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "brief")
+        assert "type" in result
+
+
+class TestProjectSummaryNormal:
+    def test_summary_normal_has_architecture(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "normal")
+        assert "architecture" in result
+        assert "autoload_details" in result["architecture"]
+
+    def test_summary_normal_has_main_scene(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "normal")
+        assert result["architecture"]["main_scene"] == "res://scenes/main.tscn"
+
+    def test_summary_normal_has_scene_structure(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "normal")
+        assert "scene_structure" in result
+        assert len(result["scene_structure"]) >= 2
+
+    def test_summary_normal_scene_has_root_type(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "normal")
+        main_scene = result["scene_structure"]["res://scenes/main.tscn"]
+        assert main_scene["root_type"] == "Node3D"
+
+    def test_summary_normal_scene_has_instances(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "normal")
+        main_scene = result["scene_structure"]["res://scenes/main.tscn"]
+        assert "res://scenes/equipment/fdm_printer.tscn" in main_scene["instances"]
+
+
+class TestProjectSummaryFull:
+    def test_summary_full_has_autoload_analysis(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "full")
+        assert "autoload_analysis" in result
+        assert len(result["autoload_analysis"]) >= 2
+
+    def test_summary_full_autoload_has_signals(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "full")
+        econ = result["autoload_analysis"]["EconomyManager"]
+        assert "cash_changed" in econ["signals"]
+
+    def test_summary_full_autoload_has_public_functions(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "full")
+        econ = result["autoload_analysis"]["EconomyManager"]
+        func_names = [f["name"] for f in econ["public_functions"]]
+        assert "add_cash" in func_names
+        assert "spend_cash" in func_names
+
+    def test_summary_full_autoload_has_referenced_by(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "full")
+        econ = result["autoload_analysis"]["EconomyManager"]
+        assert "res://scripts/autoloads/progression_manager.gd" in econ["referenced_by"]
+
+    def test_summary_full_has_file_tree(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "full")
+        assert "file_tree" in result
+        assert "scenes" in result["file_tree"]
+        assert "scripts" in result["file_tree"]
+
+    def test_summary_full_has_detected_patterns(self, session: GodotIQSession) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, "full")
+        assert "detected_patterns" in result
+        assert result["detected_patterns"]["uses_signals"] is True
+        assert result["detected_patterns"]["uses_autoloads"] is True
+
+
+class TestProjectSummaryRequiredFields:
+    """Every detail level must include the brief fields."""
+
+    @pytest.mark.parametrize("detail", ["brief", "normal", "full"])
+    def test_always_has_project_name(self, session: GodotIQSession, detail: str) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, detail)
+        assert "project_name" in result
+
+    @pytest.mark.parametrize("detail", ["brief", "normal", "full"])
+    def test_always_has_counts(self, session: GodotIQSession, detail: str) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, detail)
+        assert "counts" in result
+
+    @pytest.mark.parametrize("detail", ["brief", "normal", "full"])
+    def test_always_has_autoloads(self, session: GodotIQSession, detail: str) -> None:
+        from godotiq.tools.memory import _build_project_summary
+
+        result = _build_project_summary(session, detail)
+        assert "autoloads" in result
+
+
+class TestProjectSummaryMCPRegistration:
+    """Verify the tool is registered on the MCP server."""
+
+    @pytest.mark.asyncio
+    async def test_tool_registered(self) -> None:
+        from godotiq.server import mcp
+
+        tools = await mcp.list_tools()
+        tool_names = [t.name for t in tools]
+        assert "godotiq_project_summary" in tool_names
