Skip to content

Comments

Add project-book.ipynb interactive notebook for Wave toolkit#2

Merged
toolate28 merged 3 commits intomasterfrom
copilot/create-project-book-system
Jan 12, 2026
Merged

Add project-book.ipynb interactive notebook for Wave toolkit#2
toolate28 merged 3 commits intomasterfrom
copilot/create-project-book-system

Conversation

Copy link
Contributor

Copilot AI commented Jan 12, 2026

This pull request updates the project documentation to highlight the addition of an interactive Jupyter notebook, called the Project Book, which provides hands-on tools for framework exploration and ecosystem integration. The changes improve the visibility and accessibility of this new resource across the README.

Documentation updates:

  • Added a new "Interactive Tools" section in the README.md, introducing the Project Book as an interactive Jupyter notebook for framework tooling and ecosystem integration.
  • Updated the ecosystem tooling table in README.md to include the Project Book and its file location (project-book.ipynb).
  • Listed project-book.ipynb in the directory structure overview in README.md to reflect its presence in the repository.This pull request updates the documentation for the Wave Toolkit by introducing a new interactive resource: the Project Book Jupyter notebook. The changes highlight the addition of this notebook as a key tool for framework tooling and ecosystem integration, and update relevant sections of the README.md to reflect its presence.

Documentation updates for the new interactive tool:

  • Added a new section under "Interactive Tools" in README.md to introduce the Project Book, an interactive Jupyter notebook for framework tooling and ecosystem integration.
  • Included the Project Book in the summary table of core scripts and modules, describing it as an interactive Jupyter notebook for framework tooling.
  • Updated the project directory structure in README.md to list project-book.ipynb as part of the repository's top-level files.Adds an interactive Jupyter notebook that provides Python implementations of the Wave toolkit's core features, extended with framework tooling for the SpiralSafe ecosystem.

Core Features (Python equivalents of existing PowerShell scripts)

  • get_wave_context() - Environment capture (mirrors Get-WaveContext.ps1)
  • generate_system_prompt() - Context-aware prompt generation (mirrors New-ClaudeSystemPrompt.ps1)
  • WaveSession dataclass - Session management with logging (mirrors Invoke-ClaudeSession.ps1)

Framework Extension Tools

  • Ecosystem repository discovery across SpiralSafe repos
  • Framework structure analysis (languages, tests, docs detection)
  • Log source discovery extending Wave.Logging.psm1 patterns

Interactive Tooling

  • Context/prompt export helpers
  • AI_AGENTS.md template generator
  • Session summary generation

Example usage

# Capture environment context
ctx = get_wave_context()

# Generate Claude system prompt
prompt = generate_system_prompt(ctx)

# Create a tracked session
session = create_wave_session("Review API error handling")
session.add_log("action", "Analyzed endpoint handlers")
session.save()

README updated with navigation links and component table entries.

Original prompt

Create a project-book.pynb system llinked to main rep, with same core features, but6 expanded specifically to further tool existing frameworks


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI self-assigned this Jan 12, 2026
Copilot AI and others added 2 commits January 12, 2026 08:51
Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com>
…ry=list)

Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com>
Copilot AI changed the title [WIP] Add project-book.pynb with enhanced features Add project-book.ipynb interactive notebook for Wave toolkit Jan 12, 2026
Copilot AI requested a review from toolate28 January 12, 2026 08:55
@toolate28 toolate28 marked this pull request as ready for review January 12, 2026 10:01
Copilot AI review requested due to automatic review settings January 12, 2026 10:01
@toolate28 toolate28 merged commit 306ffa2 into master Jan 12, 2026
6 checks passed
@toolate28 toolate28 deleted the copilot/create-project-book-system branch January 12, 2026 10:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds an interactive Jupyter notebook (project-book.ipynb) that provides Python implementations of the Wave Toolkit's core PowerShell features, along with extended framework tooling for the SpiralSafe ecosystem. The notebook offers an alternative interface for working with Wave's context capture, prompt generation, and session management capabilities, plus additional tools for ecosystem exploration and repository analysis.

Changes:

  • Added project-book.ipynb - a comprehensive interactive notebook with Python implementations of Wave core features and ecosystem tooling
  • Updated README.md to document the new notebook in the Navigation section, Key Components table, and Project Structure diagram

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
project-book.ipynb New interactive Jupyter notebook providing Python implementations of Wave toolkit features, framework analysis tools, log discovery, and ecosystem integration helpers
README.md Added documentation references for the new notebook in three sections (Navigation, Key Components, and Project Structure)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +629 to +630
" # ClaudeNPC logs\n",
" cnpc_dir = home / \"repos\" / \"ClaudeNPC-Server-Suite\"\n",
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The discover_log_sources function contains hardcoded path assumptions (e.g., home / "SpiralSafe-FromGitHub", home / "repos"). These paths may not exist on all systems. While the code checks if directories exist before scanning, the hardcoded paths reduce portability. Consider making these paths configurable or documenting the expected directory structure for users.

Suggested change
" # ClaudeNPC logs\n",
" cnpc_dir = home / \"repos\" / \"ClaudeNPC-Server-Suite\"\n",
" # ClaudeNPC logs (configurable via CLAUDENPC_LOG_DIR, with a default fallback)\n",
" cnpc_dir_env = os.getenv(\"CLAUDENPC_LOG_DIR\")\n",
" if cnpc_dir_env:\n",
" cnpc_dir = Path(cnpc_dir_env).expanduser()\n",
" else:\n",
" cnpc_dir = home / \"repos\" / \"ClaudeNPC-Server-Suite\"\n",

Copilot uses AI. Check for mistakes.
" return summary\n",
"\n",
"\n",
"# Generate and display summary for demo session\n",
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notebook creates a global demo_session variable in one cell (line 295) and then modifies it in a later cell (line 908-909). This creates an implicit dependency between cells that may cause issues if cells are run out of order. Consider either documenting the cell execution order requirement or making the session management more explicit to avoid potential NameErrors if cells are executed independently.

Suggested change
"# Generate and display summary for demo session\n",
"# Generate and display summary for demo session\n",
"try:\n",
" demo_session # type: ignore[name-defined]\n",
"except NameError as exc:\n",
" raise RuntimeError(\n",
" \"demo_session is not defined. Please run the cell that creates the demo \"\n",
" \"WaveSession (the demo session setup cell) before running this one.\"\n",
" ) from exc\n",
"\n",

Copilot uses AI. Check for mistakes.
"\n",
"def is_git_repo(path: str = \".\") -> bool:\n",
" \"\"\"Check if the given path is inside a git repository.\"\"\"\n",
" return Path(path, \".git\").exists() or Path(path).joinpath(\".git\").exists()\n",
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The is_git_repo function has redundant logic. Both Path(path, ".git").exists() and Path(path).joinpath(".git").exists() check the same thing. The Path(path, ".git") constructor is equivalent to Path(path).joinpath(".git"). Only one of these checks is needed.

Suggested change
" return Path(path, \".git\").exists() or Path(path).joinpath(\".git\").exists()\n",
" return Path(path, \".git\").exists()\n",

Copilot uses AI. Check for mistakes.
"execution_count": null,
"metadata": {},
"outputs": [],
"source": "@dataclass\nclass WaveSession:\n \"\"\"Represents a Wave collaboration session.\"\"\"\n session_id: str\n timestamp: str\n context: WaveContext\n system_prompt: str\n task: Optional[str] = None\n log_entries: List[Dict[str, Any]] = field(default_factory=list)\n \n def add_log(self, entry_type: str, content: str):\n \"\"\"Add a log entry to the session.\"\"\"\n self.log_entries.append({\n \"timestamp\": datetime.now().isoformat(),\n \"type\": entry_type,\n \"content\": content\n })\n \n def save(self, output_dir: str = \".claude/logs/sessions\"):\n \"\"\"Save the session log to a file.\"\"\"\n output_path = Path(output_dir)\n output_path.mkdir(parents=True, exist_ok=True)\n \n log_file = output_path / f\"session_{self.session_id}.json\"\n \n session_data = {\n \"session_id\": self.session_id,\n \"timestamp\": self.timestamp,\n \"task\": self.task,\n \"context\": self.context.to_dict(),\n \"system_prompt\": self.system_prompt,\n \"log_entries\": self.log_entries\n }\n \n with open(log_file, \"w\", encoding=\"utf-8\") as f:\n json.dump(session_data, f, indent=2)\n \n return str(log_file)\n\n\ndef create_wave_session(task: Optional[str] = None) -> WaveSession:\n \"\"\"\n Create a new Wave session with captured context.\n \n Args:\n task: Optional task description for the session\n \n Returns:\n WaveSession object\n \"\"\"\n ctx = get_wave_context()\n session_id = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n \n session = WaveSession(\n session_id=session_id,\n timestamp=ctx.timestamp,\n context=ctx,\n system_prompt=generate_system_prompt(ctx),\n task=task\n )\n \n session.add_log(\"session_start\", f\"Session created: {session_id}\")\n if task:\n session.add_log(\"task\", task)\n \n return session\n\n\n# Create a demo session\ndemo_session = create_wave_session(\"Explore Wave Toolkit Project Book\")\nprint(f\"\ud83d\udcdd Session Created: {demo_session.session_id}\")\nprint(f\" Task: {demo_session.task}\")\nprint(f\" Log Entries: {len(demo_session.log_entries)}\")"
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The create_wave_session function creates two separate timestamps: one when creating the session_id and another when capturing context via get_wave_context(). This could result in slightly different timestamps for the session. Consider using a single timestamp captured at the start of the function for consistency, or document why two different timestamps are intentional.

Suggested change
"source": "@dataclass\nclass WaveSession:\n \"\"\"Represents a Wave collaboration session.\"\"\"\n session_id: str\n timestamp: str\n context: WaveContext\n system_prompt: str\n task: Optional[str] = None\n log_entries: List[Dict[str, Any]] = field(default_factory=list)\n \n def add_log(self, entry_type: str, content: str):\n \"\"\"Add a log entry to the session.\"\"\"\n self.log_entries.append({\n \"timestamp\": datetime.now().isoformat(),\n \"type\": entry_type,\n \"content\": content\n })\n \n def save(self, output_dir: str = \".claude/logs/sessions\"):\n \"\"\"Save the session log to a file.\"\"\"\n output_path = Path(output_dir)\n output_path.mkdir(parents=True, exist_ok=True)\n \n log_file = output_path / f\"session_{self.session_id}.json\"\n \n session_data = {\n \"session_id\": self.session_id,\n \"timestamp\": self.timestamp,\n \"task\": self.task,\n \"context\": self.context.to_dict(),\n \"system_prompt\": self.system_prompt,\n \"log_entries\": self.log_entries\n }\n \n with open(log_file, \"w\", encoding=\"utf-8\") as f:\n json.dump(session_data, f, indent=2)\n \n return str(log_file)\n\n\ndef create_wave_session(task: Optional[str] = None) -> WaveSession:\n \"\"\"\n Create a new Wave session with captured context.\n \n Args:\n task: Optional task description for the session\n \n Returns:\n WaveSession object\n \"\"\"\n ctx = get_wave_context()\n session_id = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n \n session = WaveSession(\n session_id=session_id,\n timestamp=ctx.timestamp,\n context=ctx,\n system_prompt=generate_system_prompt(ctx),\n task=task\n )\n \n session.add_log(\"session_start\", f\"Session created: {session_id}\")\n if task:\n session.add_log(\"task\", task)\n \n return session\n\n\n# Create a demo session\ndemo_session = create_wave_session(\"Explore Wave Toolkit Project Book\")\nprint(f\"\ud83d\udcdd Session Created: {demo_session.session_id}\")\nprint(f\" Task: {demo_session.task}\")\nprint(f\" Log Entries: {len(demo_session.log_entries)}\")"
"source": "@dataclass\nclass WaveSession:\n \"\"\"Represents a Wave collaboration session.\"\"\"\n session_id: str\n timestamp: str\n context: WaveContext\n system_prompt: str\n task: Optional[str] = None\n log_entries: List[Dict[str, Any]] = field(default_factory=list)\n \n def add_log(self, entry_type: str, content: str):\n \"\"\"Add a log entry to the session.\"\"\"\n self.log_entries.append({\n \"timestamp\": datetime.now().isoformat(),\n \"type\": entry_type,\n \"content\": content\n })\n \n def save(self, output_dir: str = \".claude/logs/sessions\"):\n \"\"\"Save the session log to a file.\"\"\"\n output_path = Path(output_dir)\n output_path.mkdir(parents=True, exist_ok=True)\n \n log_file = output_path / f\"session_{self.session_id}.json\"\n \n session_data = {\n \"session_id\": self.session_id,\n \"timestamp\": self.timestamp,\n \"task\": self.task,\n \"context\": self.context.to_dict(),\n \"system_prompt\": self.system_prompt,\n \"log_entries\": self.log_entries\n }\n \n with open(log_file, \"w\", encoding=\"utf-8\") as f:\n json.dump(session_data, f, indent=2)\n \n return str(log_file)\n\n\ndef create_wave_session(task: Optional[str] = None) -> WaveSession:\n \"\"\"\n Create a new Wave session with captured context.\n\n The session timestamp (`WaveSession.timestamp`) is taken from the\n captured `WaveContext` (`ctx.timestamp`), which records when the\n environment/context snapshot was created. The `session_id` is a\n human-readable identifier generated at session construction time\n and may differ slightly from `ctx.timestamp`.\n \n Args:\n task: Optional task description for the session\n \n Returns:\n WaveSession object\n \"\"\"\n # Capture context (and its timestamp) first; `session_id` is generated\n # separately and may differ slightly in time from `ctx.timestamp`.\n ctx = get_wave_context()\n session_id = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n \n session = WaveSession(\n session_id=session_id,\n timestamp=ctx.timestamp,\n context=ctx,\n system_prompt=generate_system_prompt(ctx),\n task=task\n )\n \n session.add_log(\"session_start\", f\"Session created: {session_id}\")\n if task:\n session.add_log(\"task\", task)\n \n return session\n\n\n# Create a demo session\ndemo_session = create_wave_session(\"Explore Wave Toolkit Project Book\")\nprint(f\"\ud83d\udcdd Session Created: {demo_session.session_id}\")\nprint(f\" Task: {demo_session.task}\")\nprint(f\" Log Entries: {len(demo_session.log_entries)}\")"

Copilot uses AI. Check for mistakes.
Comment on lines +493 to +505
" for item in path.rglob(\"*\"):\n",
" # Skip hidden directories and common ignore patterns\n",
" if any(part.startswith(\".\") for part in item.parts):\n",
" continue\n",
" if \"node_modules\" in item.parts or \"__pycache__\" in item.parts:\n",
" continue\n",
" \n",
" if item.is_file():\n",
" file_count += 1\n",
" ext = item.suffix.lower()\n",
" if ext in lang_extensions:\n",
" lang = lang_extensions[ext]\n",
" languages[lang] = languages.get(lang, 0) + 1\n",
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The analyze_framework function uses path.rglob("*") which will recursively scan all files in a repository. For large repositories, this could be slow. While the code does skip common directories like node_modules and __pycache__, this happens after iteration, not before. Consider using a more efficient approach or documenting the performance characteristics for large repositories.

Suggested change
" for item in path.rglob(\"*\"):\n",
" # Skip hidden directories and common ignore patterns\n",
" if any(part.startswith(\".\") for part in item.parts):\n",
" continue\n",
" if \"node_modules\" in item.parts or \"__pycache__\" in item.parts:\n",
" continue\n",
" \n",
" if item.is_file():\n",
" file_count += 1\n",
" ext = item.suffix.lower()\n",
" if ext in lang_extensions:\n",
" lang = lang_extensions[ext]\n",
" languages[lang] = languages.get(lang, 0) + 1\n",
" import os\n",
" for root, dirs, files in os.walk(path):\n",
" # Prune hidden and common large/temporary directories before descending\n",
" dirs[:] = [\n",
" d for d in dirs\n",
" if not d.startswith(\".\") and d not in {\"node_modules\", \"__pycache__\"}\n",
" ]\n",
" root_path = Path(root)\n",
" for filename in files:\n",
" # Skip hidden files\n",
" if filename.startswith(\".\"):\n",
" continue\n",
" item = root_path / filename\n",
" if item.is_file():\n",
" file_count += 1\n",
" ext = item.suffix.lower()\n",
" if ext in lang_extensions:\n",
" lang = lang_extensions[ext]\n",
" languages[lang] = languages.get(lang, 0) + 1\n",

Copilot uses AI. Check for mistakes.
@toolate28
Copy link
Owner

@copilot these changes too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants