From 20ee073df8ffa34bcabc5aa85fa4d4f58af1a25b Mon Sep 17 00:00:00 2001 From: Noah Horton Date: Sun, 22 Feb 2026 13:30:33 -0700 Subject: [PATCH 1/3] Add template agent support to create-agent skill Allow seeding a new LearningAgent from an existing one by passing an optional template path. Copies core-knowledge.md, topics, and learnings from the template as a starting point, which the user can then customize. Co-Authored-By: Claude Opus 4.6 --- learning_agents/scripts/create_agent.sh | 60 ++++++++++++++++++-- learning_agents/skills/create-agent/SKILL.md | 25 ++++++-- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/learning_agents/scripts/create_agent.sh b/learning_agents/scripts/create_agent.sh index b6d8e88c..8435a240 100755 --- a/learning_agents/scripts/create_agent.sh +++ b/learning_agents/scripts/create_agent.sh @@ -1,7 +1,14 @@ #!/bin/bash # create_agent.sh - Create a new LearningAgent scaffold # -# Usage: create_agent.sh +# Usage: create_agent.sh [template-agent-path] +# +# Arguments: +# agent-name Name for the new agent (use dashes for multi-word) +# template-agent-path Optional path to an existing learning agent directory +# (e.g., .deepwork/learning-agents/my-existing-agent) +# If provided, copies core-knowledge.md, topics/*, and +# learnings/* from the template into the new agent. # # Creates: # .deepwork/learning-agents//core-knowledge.md @@ -13,12 +20,25 @@ set -euo pipefail AGENT_NAME="${1:-}" +TEMPLATE_PATH="${2:-}" if [ -z "$AGENT_NAME" ]; then - echo "Usage: create_agent.sh " >&2 + echo "Usage: create_agent.sh [template-agent-path]" >&2 exit 1 fi +# Validate template path if provided +if [ -n "$TEMPLATE_PATH" ]; then + if [ ! -d "$TEMPLATE_PATH" ]; then + echo "Template agent directory not found: ${TEMPLATE_PATH}" >&2 + exit 1 + fi + if [ ! -f "$TEMPLATE_PATH/core-knowledge.md" ]; then + echo "Template directory missing core-knowledge.md: ${TEMPLATE_PATH}" >&2 + exit 1 + fi +fi + AGENT_DIR=".deepwork/learning-agents/${AGENT_NAME}" CLAUDE_AGENT_FILE=".claude/agents/${AGENT_NAME}.md" @@ -55,8 +75,39 @@ These files let you customize how the learning cycle works for this agent. Each - **learning_from_issues.md** — Included during the `incorporate-learnings` step. Use this to guide how learnings are integrated — e.g., preferences for topics vs learnings, naming conventions, or areas of core-knowledge that should stay concise. ALG_README - # Create core-knowledge.md with TODO placeholder - cat > "${AGENT_DIR}/core-knowledge.md" << 'CORE_KNOWLEDGE' + # ======================================================================== + # SEED FROM TEMPLATE OR CREATE EMPTY + # ======================================================================== + + if [ -n "$TEMPLATE_PATH" ]; then + # Copy core-knowledge.md from template + cp "$TEMPLATE_PATH/core-knowledge.md" "${AGENT_DIR}/core-knowledge.md" + echo "Copied core-knowledge.md from template" + + # Copy topics (if any exist beyond .gitkeep) + TOPIC_COUNT=0 + for f in "$TEMPLATE_PATH/topics/"*.md; do + [ -f "$f" ] || continue + cp "$f" "${AGENT_DIR}/topics/" + TOPIC_COUNT=$((TOPIC_COUNT + 1)) + done + if [ "$TOPIC_COUNT" -gt 0 ]; then + echo "Copied ${TOPIC_COUNT} topic(s) from template" + fi + + # Copy learnings (if any exist beyond .gitkeep) + LEARNING_COUNT=0 + for f in "$TEMPLATE_PATH/learnings/"*.md; do + [ -f "$f" ] || continue + cp "$f" "${AGENT_DIR}/learnings/" + LEARNING_COUNT=$((LEARNING_COUNT + 1)) + done + if [ "$LEARNING_COUNT" -gt 0 ]; then + echo "Copied ${LEARNING_COUNT} learning(s) from template" + fi + else + # Create core-knowledge.md with TODO placeholder + cat > "${AGENT_DIR}/core-knowledge.md" << 'CORE_KNOWLEDGE' TODO: Complete current knowledge of this domain. Written in second person ("You should...") because this text becomes the agent's system instructions. Structure it as: @@ -66,6 +117,7 @@ becomes the agent's system instructions. Structure it as: 4. Pitfalls to avoid 5. Decision frameworks CORE_KNOWLEDGE + fi echo "Created agent directory: ${AGENT_DIR}" fi diff --git a/learning_agents/skills/create-agent/SKILL.md b/learning_agents/skills/create-agent/SKILL.md index 2072aa1a..3bf1e75b 100644 --- a/learning_agents/skills/create-agent/SKILL.md +++ b/learning_agents/skills/create-agent/SKILL.md @@ -9,24 +9,37 @@ Create a new LearningAgent and guide the user through initial configuration. ## Arguments -`$ARGUMENTS` is the agent name. Use dashes for multi-word names (e.g., `rails-activejob`). If not provided, ask the user what to name the agent. +`$ARGUMENTS` contains the agent name and an optional template path, separated by whitespace. + +- **Agent name** (required): Use dashes for multi-word names (e.g., `rails-activejob`). If not provided, ask the user what to name the agent. +- **Template agent path** (optional): Path to an existing learning agent directory (e.g., `.deepwork/learning-agents/my-existing-agent`). If provided, the new agent is seeded with the template's `core-knowledge.md`, `topics/`, and `learnings/` as a starting point. The user can then customize the copied content during configuration. ## Procedure ### Step 1: Validate and Run Scaffold Script +Parse `$ARGUMENTS` to extract the agent name (first word) and optional template path (second word, if present). + If the name contains spaces or uppercase letters, normalize to lowercase dashes (e.g., "Rails ActiveJob" → `rails-activejob`). Check `.claude/agents/` for an existing file matching `.md`. If found, inform the user of the conflict and ask how to proceed. +If a template path was provided, verify it exists and contains `core-knowledge.md`. If not, inform the user and ask how to proceed. + Run the scaffold script: ```bash -${CLAUDE_PLUGIN_ROOT}/scripts/create_agent.sh $ARGUMENTS +# Without template: +${CLAUDE_PLUGIN_ROOT}/scripts/create_agent.sh + +# With template: +${CLAUDE_PLUGIN_ROOT}/scripts/create_agent.sh ``` If the script reports that directories already exist, inform the user and ask whether to proceed with updating the configuration or stop. +If a template was used, inform the user what was copied (the script output will list the counts). + ### Step 2: Configure the Agent Ask the user about the agent's domain: @@ -34,9 +47,11 @@ Ask the user about the agent's domain: - What domain or area of expertise does this agent cover? - What kinds of tasks will it be delegated to handle? +If a template was used, read the copied `core-knowledge.md` and present it to the user. Ask if they want to keep it as-is, modify it for the new agent's focus, or replace it entirely. + Based on their answers, update: -1. **`.deepwork/learning-agents//core-knowledge.md`**: Replace the TODO content with the agent's core expertise in second person ("You should...", "You are an expert on..."). +1. **`.deepwork/learning-agents//core-knowledge.md`**: If created from scratch, replace the TODO content with the agent's core expertise in second person ("You should...", "You are an expert on..."). If seeded from a template, adapt the content to reflect the new agent's specific focus area. Example: ``` @@ -52,7 +67,9 @@ Based on their answers, update: ### Step 3: Seed Initial Knowledge (Optional) -Ask the user if they want to seed any initial topics or learnings. If yes, create files using these formats: +If a template was used and topics/learnings were copied, list what was copied and ask if the user wants to review, remove, or add to them. + +Otherwise, ask the user if they want to seed any initial topics or learnings. If yes, create files using these formats: **Topic file** (`.deepwork/learning-agents//topics/.md`): ```yaml From 1443bc0c1f9812b3d5e26b8df1758ccbd74f4bd0 Mon Sep 17 00:00:00 2001 From: Noah Horton Date: Sun, 22 Feb 2026 13:40:21 -0700 Subject: [PATCH 2/3] Add requirements and tests for template agent creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add REQ-002.16 through REQ-002.24 covering template-based agent seeding (validation, copying, reporting, skill guidance). Update REQ-002.5 and REQ-002.6 to reflect the optional template argument. Add 16 tests for create_agent.sh covering both baseline and template flows — all passing. Co-Authored-By: Claude Opus 4.6 --- .../learning-agents/REQ-002-agent-creation.md | 40 ++- tests/unit/test_create_agent_script.py | 238 ++++++++++++++++++ 2 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 tests/unit/test_create_agent_script.py diff --git a/specs/learning-agents/REQ-002-agent-creation.md b/specs/learning-agents/REQ-002-agent-creation.md index 5af4532e..387bde51 100644 --- a/specs/learning-agents/REQ-002-agent-creation.md +++ b/specs/learning-agents/REQ-002-agent-creation.md @@ -24,12 +24,12 @@ If the agent directory `.deepwork/learning-agents//` already exists, ### REQ-002.5: Scaffold Script Execution -The skill MUST execute the scaffold script at `${CLAUDE_PLUGIN_ROOT}/scripts/create_agent.sh` passing the normalized agent name as the argument. +The skill MUST execute the scaffold script at `${CLAUDE_PLUGIN_ROOT}/scripts/create_agent.sh` passing the normalized agent name as the first argument and, when a template path is provided, the template path as the second argument. ### REQ-002.6: Scaffold Script -- Agent Directory Creation The `create_agent.sh` script MUST create the following directory structure when the agent directory does not exist: -- `.deepwork/learning-agents//core-knowledge.md` -- with TODO placeholder content +- `.deepwork/learning-agents//core-knowledge.md` -- with TODO placeholder content (when no template is provided; see REQ-002.19 for template behavior) - `.deepwork/learning-agents//topics/` -- with `.gitkeep` - `.deepwork/learning-agents//learnings/` -- with `.gitkeep` - `.deepwork/learning-agents//additional_learning_guidelines/` -- containing `README.md`, `issue_identification.md`, `issue_investigation.md`, and `learning_from_issues.md` @@ -75,3 +75,39 @@ Upon completion, the skill MUST output a summary listing all files created or mo ### REQ-002.15: No Overwrites Without Confirmation The skill MUST NOT overwrite any existing file without explicit user confirmation. + +### REQ-002.16: Scaffold Script -- Template Agent Argument + +The `create_agent.sh` script MUST accept an optional second positional argument `[template-agent-path]` specifying the path to an existing LearningAgent directory. When not provided, the script MUST behave identically to the non-template flow (creating TODO placeholder content in `core-knowledge.md`). + +### REQ-002.17: Scaffold Script -- Template Validation -- Directory Existence + +When a template path argument is provided, the script MUST verify that the path is an existing directory. If the directory does not exist, the script MUST print an error message containing the path to stderr and exit with code 1. + +### REQ-002.18: Scaffold Script -- Template Validation -- Core Knowledge Required + +When a template path argument is provided and the directory exists, the script MUST verify that the template directory contains a `core-knowledge.md` file. If the file is missing, the script MUST print an error message containing the path to stderr and exit with code 1. + +### REQ-002.19: Scaffold Script -- Template Seeding -- Core Knowledge + +When a valid template path is provided, the script MUST copy `core-knowledge.md` from the template directory into the new agent's directory instead of creating the TODO placeholder content. + +### REQ-002.20: Scaffold Script -- Template Seeding -- Topics + +When a valid template path is provided, the script MUST copy all `.md` files from the template's `topics/` directory into the new agent's `topics/` directory. If no `.md` files exist in the template's `topics/` directory, the new agent's `topics/` directory MUST remain empty (aside from `.gitkeep`). + +### REQ-002.21: Scaffold Script -- Template Seeding -- Learnings + +When a valid template path is provided, the script MUST copy all `.md` files from the template's `learnings/` directory into the new agent's `learnings/` directory. If no `.md` files exist in the template's `learnings/` directory, the new agent's `learnings/` directory MUST remain empty (aside from `.gitkeep`). + +### REQ-002.22: Scaffold Script -- Template Copy Reporting + +When files are copied from a template, the script MUST output a confirmation message for the core-knowledge copy. The script MUST output the count of copied topic files when at least one topic was copied. The script MUST output the count of copied learning files when at least one learning was copied. + +### REQ-002.23: Skill -- Template Configuration Guidance + +When a template was used, the skill MUST read the copied `core-knowledge.md` and present it to the user, asking whether to keep it as-is, modify it for the new agent's focus, or replace it entirely. The skill MUST also list any copied topics and learnings and offer the user the opportunity to review, remove, or add to them. + +### REQ-002.24: Skill -- Template Argument Parsing + +The skill MUST parse `$ARGUMENTS` to extract the agent name (first token) and an optional template path (second token). Both tokens MUST be passed to the scaffold script as separate positional arguments. diff --git a/tests/unit/test_create_agent_script.py b/tests/unit/test_create_agent_script.py new file mode 100644 index 00000000..208b9806 --- /dev/null +++ b/tests/unit/test_create_agent_script.py @@ -0,0 +1,238 @@ +"""Tests for create_agent.sh -- validates learning-agents REQ-002. + +These tests validate the scaffold script behavior for agent creation, +including template-based agent seeding (REQ-002.16 through REQ-002.22). +""" + +import subprocess +from pathlib import Path + +import pytest + +SCRIPT_PATH = ( + Path(__file__).resolve().parents[2] + / "learning_agents" + / "scripts" + / "create_agent.sh" +) + + +@pytest.fixture +def work_dir(tmp_path: Path) -> Path: + """Create a working directory simulating a project root.""" + (tmp_path / ".deepwork" / "learning-agents").mkdir(parents=True) + (tmp_path / ".claude" / "agents").mkdir(parents=True) + return tmp_path + + +@pytest.fixture +def template_agent(tmp_path: Path) -> Path: + """Create a template agent with core-knowledge, topics, and learnings.""" + template = tmp_path / "template-agent" + template.mkdir() + (template / "core-knowledge.md").write_text( + "You are an expert on template domain.\n" + ) + + topics = template / "topics" + topics.mkdir() + (topics / ".gitkeep").touch() + (topics / "topic-one.md").write_text("---\nname: Topic One\n---\nContent.\n") + (topics / "topic-two.md").write_text("---\nname: Topic Two\n---\nContent.\n") + + learnings = template / "learnings" + learnings.mkdir() + (learnings / ".gitkeep").touch() + (learnings / "learning-one.md").write_text( + "---\nname: Learning One\n---\nContent.\n" + ) + + return template + + +def run_script( + work_dir: Path, agent_name: str, template_path: str | None = None +) -> subprocess.CompletedProcess[str]: + cmd = [str(SCRIPT_PATH), agent_name] + if template_path is not None: + cmd.append(template_path) + return subprocess.run(cmd, cwd=work_dir, capture_output=True, text=True, timeout=30) + + +class TestBaselineCreation: + """Non-template agent creation (REQ-002.6, REQ-002.8, REQ-002.10, REQ-002.11).""" + + # REQ-002.11 + def test_no_args_exits_with_error(self, work_dir: Path) -> None: + result = subprocess.run( + [str(SCRIPT_PATH)], cwd=work_dir, capture_output=True, text=True + ) + assert result.returncode == 1 + assert "Usage:" in result.stderr + + # REQ-002.6 + def test_creates_directory_structure(self, work_dir: Path) -> None: + result = run_script(work_dir, "test-agent") + assert result.returncode == 0 + + agent_dir = work_dir / ".deepwork" / "learning-agents" / "test-agent" + assert (agent_dir / "core-knowledge.md").is_file() + assert (agent_dir / "topics" / ".gitkeep").is_file() + assert (agent_dir / "learnings" / ".gitkeep").is_file() + assert (agent_dir / "additional_learning_guidelines" / "README.md").is_file() + + # REQ-002.6 + def test_creates_todo_placeholder_without_template(self, work_dir: Path) -> None: + run_script(work_dir, "test-agent") + content = ( + work_dir / ".deepwork" / "learning-agents" / "test-agent" / "core-knowledge.md" + ).read_text() + assert "TODO" in content + + # REQ-002.8 + def test_creates_claude_agent_file(self, work_dir: Path) -> None: + result = run_script(work_dir, "test-agent") + assert result.returncode == 0 + + agent_file = work_dir / ".claude" / "agents" / "test-agent.md" + assert agent_file.is_file() + content = agent_file.read_text() + assert "name: TODO" in content + + # REQ-002.10 + def test_idempotent_does_not_overwrite(self, work_dir: Path) -> None: + run_script(work_dir, "test-agent") + ck = work_dir / ".deepwork" / "learning-agents" / "test-agent" / "core-knowledge.md" + ck.write_text("Custom content\n") + + result = run_script(work_dir, "test-agent") + assert result.returncode == 0 + assert "already exists" in result.stderr + assert ck.read_text() == "Custom content\n" + + +class TestTemplateCreation: + """Template-based agent creation (REQ-002.16 through REQ-002.22).""" + + # REQ-002.16 + def test_accepts_optional_template_argument( + self, work_dir: Path, template_agent: Path + ) -> None: + result = run_script(work_dir, "new-agent", str(template_agent)) + assert result.returncode == 0 + + # REQ-002.16 + def test_without_template_creates_todo(self, work_dir: Path) -> None: + run_script(work_dir, "new-agent") + content = ( + work_dir / ".deepwork" / "learning-agents" / "new-agent" / "core-knowledge.md" + ).read_text() + assert "TODO" in content + + # REQ-002.17 + def test_nonexistent_template_directory_exits_1(self, work_dir: Path) -> None: + result = run_script(work_dir, "new-agent", "/nonexistent/path") + assert result.returncode == 1 + assert "/nonexistent/path" in result.stderr + + # REQ-002.18 + def test_template_missing_core_knowledge_exits_1( + self, work_dir: Path, tmp_path: Path + ) -> None: + empty_template = tmp_path / "empty-template" + empty_template.mkdir() + + result = run_script(work_dir, "new-agent", str(empty_template)) + assert result.returncode == 1 + assert "core-knowledge.md" in result.stderr + + # REQ-002.19 + def test_copies_core_knowledge_from_template( + self, work_dir: Path, template_agent: Path + ) -> None: + run_script(work_dir, "new-agent", str(template_agent)) + content = ( + work_dir / ".deepwork" / "learning-agents" / "new-agent" / "core-knowledge.md" + ).read_text() + assert "TODO" not in content + assert "template domain" in content + + # REQ-002.20 + def test_copies_topics_from_template( + self, work_dir: Path, template_agent: Path + ) -> None: + run_script(work_dir, "new-agent", str(template_agent)) + topics_dir = work_dir / ".deepwork" / "learning-agents" / "new-agent" / "topics" + topic_files = sorted(f.name for f in topics_dir.glob("*.md")) + assert topic_files == ["topic-one.md", "topic-two.md"] + + # REQ-002.20 + def test_no_template_topics_leaves_empty( + self, work_dir: Path, tmp_path: Path + ) -> None: + template = tmp_path / "no-topics" + template.mkdir() + (template / "core-knowledge.md").write_text("Content.\n") + (template / "topics").mkdir() + (template / "topics" / ".gitkeep").touch() + (template / "learnings").mkdir() + + run_script(work_dir, "new-agent", str(template)) + md_files = list( + (work_dir / ".deepwork" / "learning-agents" / "new-agent" / "topics").glob("*.md") + ) + assert len(md_files) == 0 + + # REQ-002.21 + def test_copies_learnings_from_template( + self, work_dir: Path, template_agent: Path + ) -> None: + run_script(work_dir, "new-agent", str(template_agent)) + learnings_dir = ( + work_dir / ".deepwork" / "learning-agents" / "new-agent" / "learnings" + ) + learning_files = [f.name for f in learnings_dir.glob("*.md")] + assert "learning-one.md" in learning_files + + # REQ-002.21 + def test_no_template_learnings_leaves_empty( + self, work_dir: Path, tmp_path: Path + ) -> None: + template = tmp_path / "no-learnings" + template.mkdir() + (template / "core-knowledge.md").write_text("Content.\n") + (template / "topics").mkdir() + (template / "learnings").mkdir() + (template / "learnings" / ".gitkeep").touch() + + run_script(work_dir, "new-agent", str(template)) + md_files = list( + (work_dir / ".deepwork" / "learning-agents" / "new-agent" / "learnings").glob( + "*.md" + ) + ) + assert len(md_files) == 0 + + # REQ-002.22 + def test_reports_copy_counts( + self, work_dir: Path, template_agent: Path + ) -> None: + result = run_script(work_dir, "new-agent", str(template_agent)) + assert "Copied core-knowledge.md from template" in result.stdout + assert "2 topic(s)" in result.stdout + assert "1 learning(s)" in result.stdout + + # REQ-002.22 + def test_no_copies_no_count_messages( + self, work_dir: Path, tmp_path: Path + ) -> None: + template = tmp_path / "minimal" + template.mkdir() + (template / "core-knowledge.md").write_text("Content.\n") + (template / "topics").mkdir() + (template / "learnings").mkdir() + + result = run_script(work_dir, "new-agent", str(template)) + assert "Copied core-knowledge.md from template" in result.stdout + assert "topic(s)" not in result.stdout + assert "learning(s)" not in result.stdout From e56e959b24243a0698a7cff994b20d0c534836ba Mon Sep 17 00:00:00 2001 From: Noah Horton Date: Sun, 22 Feb 2026 13:45:40 -0700 Subject: [PATCH 3/3] Fix ruff formatting in test_create_agent_script.py Co-Authored-By: Claude Opus 4.6 --- tests/unit/test_create_agent_script.py | 57 +++++++------------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/tests/unit/test_create_agent_script.py b/tests/unit/test_create_agent_script.py index 208b9806..4063cbae 100644 --- a/tests/unit/test_create_agent_script.py +++ b/tests/unit/test_create_agent_script.py @@ -10,10 +10,7 @@ import pytest SCRIPT_PATH = ( - Path(__file__).resolve().parents[2] - / "learning_agents" - / "scripts" - / "create_agent.sh" + Path(__file__).resolve().parents[2] / "learning_agents" / "scripts" / "create_agent.sh" ) @@ -30,9 +27,7 @@ def template_agent(tmp_path: Path) -> Path: """Create a template agent with core-knowledge, topics, and learnings.""" template = tmp_path / "template-agent" template.mkdir() - (template / "core-knowledge.md").write_text( - "You are an expert on template domain.\n" - ) + (template / "core-knowledge.md").write_text("You are an expert on template domain.\n") topics = template / "topics" topics.mkdir() @@ -43,9 +38,7 @@ def template_agent(tmp_path: Path) -> Path: learnings = template / "learnings" learnings.mkdir() (learnings / ".gitkeep").touch() - (learnings / "learning-one.md").write_text( - "---\nname: Learning One\n---\nContent.\n" - ) + (learnings / "learning-one.md").write_text("---\nname: Learning One\n---\nContent.\n") return template @@ -64,9 +57,7 @@ class TestBaselineCreation: # REQ-002.11 def test_no_args_exits_with_error(self, work_dir: Path) -> None: - result = subprocess.run( - [str(SCRIPT_PATH)], cwd=work_dir, capture_output=True, text=True - ) + result = subprocess.run([str(SCRIPT_PATH)], cwd=work_dir, capture_output=True, text=True) assert result.returncode == 1 assert "Usage:" in result.stderr @@ -115,9 +106,7 @@ class TestTemplateCreation: """Template-based agent creation (REQ-002.16 through REQ-002.22).""" # REQ-002.16 - def test_accepts_optional_template_argument( - self, work_dir: Path, template_agent: Path - ) -> None: + def test_accepts_optional_template_argument(self, work_dir: Path, template_agent: Path) -> None: result = run_script(work_dir, "new-agent", str(template_agent)) assert result.returncode == 0 @@ -136,9 +125,7 @@ def test_nonexistent_template_directory_exits_1(self, work_dir: Path) -> None: assert "/nonexistent/path" in result.stderr # REQ-002.18 - def test_template_missing_core_knowledge_exits_1( - self, work_dir: Path, tmp_path: Path - ) -> None: + def test_template_missing_core_knowledge_exits_1(self, work_dir: Path, tmp_path: Path) -> None: empty_template = tmp_path / "empty-template" empty_template.mkdir() @@ -158,18 +145,14 @@ def test_copies_core_knowledge_from_template( assert "template domain" in content # REQ-002.20 - def test_copies_topics_from_template( - self, work_dir: Path, template_agent: Path - ) -> None: + def test_copies_topics_from_template(self, work_dir: Path, template_agent: Path) -> None: run_script(work_dir, "new-agent", str(template_agent)) topics_dir = work_dir / ".deepwork" / "learning-agents" / "new-agent" / "topics" topic_files = sorted(f.name for f in topics_dir.glob("*.md")) assert topic_files == ["topic-one.md", "topic-two.md"] # REQ-002.20 - def test_no_template_topics_leaves_empty( - self, work_dir: Path, tmp_path: Path - ) -> None: + def test_no_template_topics_leaves_empty(self, work_dir: Path, tmp_path: Path) -> None: template = tmp_path / "no-topics" template.mkdir() (template / "core-knowledge.md").write_text("Content.\n") @@ -184,20 +167,14 @@ def test_no_template_topics_leaves_empty( assert len(md_files) == 0 # REQ-002.21 - def test_copies_learnings_from_template( - self, work_dir: Path, template_agent: Path - ) -> None: + def test_copies_learnings_from_template(self, work_dir: Path, template_agent: Path) -> None: run_script(work_dir, "new-agent", str(template_agent)) - learnings_dir = ( - work_dir / ".deepwork" / "learning-agents" / "new-agent" / "learnings" - ) + learnings_dir = work_dir / ".deepwork" / "learning-agents" / "new-agent" / "learnings" learning_files = [f.name for f in learnings_dir.glob("*.md")] assert "learning-one.md" in learning_files # REQ-002.21 - def test_no_template_learnings_leaves_empty( - self, work_dir: Path, tmp_path: Path - ) -> None: + def test_no_template_learnings_leaves_empty(self, work_dir: Path, tmp_path: Path) -> None: template = tmp_path / "no-learnings" template.mkdir() (template / "core-knowledge.md").write_text("Content.\n") @@ -207,25 +184,19 @@ def test_no_template_learnings_leaves_empty( run_script(work_dir, "new-agent", str(template)) md_files = list( - (work_dir / ".deepwork" / "learning-agents" / "new-agent" / "learnings").glob( - "*.md" - ) + (work_dir / ".deepwork" / "learning-agents" / "new-agent" / "learnings").glob("*.md") ) assert len(md_files) == 0 # REQ-002.22 - def test_reports_copy_counts( - self, work_dir: Path, template_agent: Path - ) -> None: + def test_reports_copy_counts(self, work_dir: Path, template_agent: Path) -> None: result = run_script(work_dir, "new-agent", str(template_agent)) assert "Copied core-knowledge.md from template" in result.stdout assert "2 topic(s)" in result.stdout assert "1 learning(s)" in result.stdout # REQ-002.22 - def test_no_copies_no_count_messages( - self, work_dir: Path, tmp_path: Path - ) -> None: + def test_no_copies_no_count_messages(self, work_dir: Path, tmp_path: Path) -> None: template = tmp_path / "minimal" template.mkdir() (template / "core-knowledge.md").write_text("Content.\n")