klaude-code 1.2.22__py3-none-any.whl → 1.2.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- klaude_code/command/prompt-jj-describe.md +32 -0
- klaude_code/command/status_cmd.py +1 -1
- klaude_code/{const/__init__.py → const.py} +11 -2
- klaude_code/core/executor.py +1 -1
- klaude_code/core/manager/sub_agent_manager.py +1 -1
- klaude_code/core/reminders.py +51 -0
- klaude_code/core/task.py +37 -18
- klaude_code/core/tool/__init__.py +1 -4
- klaude_code/core/tool/file/read_tool.py +23 -1
- klaude_code/core/tool/file/write_tool.py +7 -3
- klaude_code/core/tool/skill/__init__.py +0 -0
- klaude_code/core/tool/{memory → skill}/skill_tool.py +16 -39
- klaude_code/llm/openai_compatible/client.py +29 -102
- klaude_code/llm/openai_compatible/stream.py +272 -0
- klaude_code/llm/openrouter/client.py +29 -109
- klaude_code/llm/openrouter/{reasoning_handler.py → reasoning.py} +24 -2
- klaude_code/protocol/model.py +15 -2
- klaude_code/session/export.py +1 -1
- klaude_code/session/store.py +4 -2
- klaude_code/skill/__init__.py +27 -0
- klaude_code/skill/assets/deslop/SKILL.md +17 -0
- klaude_code/skill/assets/dev-docs/SKILL.md +108 -0
- klaude_code/skill/assets/handoff/SKILL.md +39 -0
- klaude_code/skill/assets/jj-workspace/SKILL.md +20 -0
- klaude_code/skill/assets/skill-creator/SKILL.md +139 -0
- klaude_code/{core/tool/memory/skill_loader.py → skill/loader.py} +60 -24
- klaude_code/skill/manager.py +70 -0
- klaude_code/skill/system_skills.py +192 -0
- klaude_code/ui/core/stage_manager.py +0 -3
- klaude_code/ui/modes/repl/completers.py +103 -3
- klaude_code/ui/modes/repl/event_handler.py +101 -49
- klaude_code/ui/modes/repl/input_prompt_toolkit.py +55 -6
- klaude_code/ui/modes/repl/renderer.py +24 -17
- klaude_code/ui/renderers/assistant.py +7 -2
- klaude_code/ui/renderers/developer.py +12 -0
- klaude_code/ui/renderers/diffs.py +1 -1
- klaude_code/ui/renderers/metadata.py +6 -8
- klaude_code/ui/renderers/sub_agent.py +28 -5
- klaude_code/ui/renderers/thinking.py +16 -10
- klaude_code/ui/renderers/tools.py +83 -34
- klaude_code/ui/renderers/user_input.py +32 -2
- klaude_code/ui/rich/markdown.py +40 -20
- klaude_code/ui/rich/status.py +15 -19
- klaude_code/ui/rich/theme.py +70 -17
- {klaude_code-1.2.22.dist-info → klaude_code-1.2.24.dist-info}/METADATA +18 -13
- {klaude_code-1.2.22.dist-info → klaude_code-1.2.24.dist-info}/RECORD +49 -45
- klaude_code/command/prompt-deslop.md +0 -14
- klaude_code/command/prompt-dev-docs-update.md +0 -56
- klaude_code/command/prompt-dev-docs.md +0 -46
- klaude_code/command/prompt-handoff.md +0 -33
- klaude_code/command/prompt-jj-workspace.md +0 -18
- klaude_code/core/tool/memory/__init__.py +0 -5
- klaude_code/llm/openai_compatible/stream_processor.py +0 -83
- /klaude_code/core/tool/{memory → skill}/skill_tool.md +0 -0
- {klaude_code-1.2.22.dist-info → klaude_code-1.2.24.dist-info}/WHEEL +0 -0
- {klaude_code-1.2.22.dist-info → klaude_code-1.2.24.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-docs
|
|
3
|
+
description: Manage development documentation for complex tasks. Use this skill when users want to create a strategic plan with structured task breakdown, or update development documentation before context compaction/reset. Triggers include "create a plan", "dev docs", "update docs before context reset", "context limit approaching".
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Create and update development documentation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Dev Docs
|
|
9
|
+
|
|
10
|
+
Manage development documentation for complex, multi-phase tasks. This skill supports two workflows:
|
|
11
|
+
1. **Create**: Generate a comprehensive strategic plan with structured task breakdown
|
|
12
|
+
2. **Update**: Update documentation before context compaction or reset
|
|
13
|
+
|
|
14
|
+
## Create Development Plan
|
|
15
|
+
|
|
16
|
+
When creating a new plan:
|
|
17
|
+
|
|
18
|
+
1. **Analyze the request** and determine the scope of planning needed
|
|
19
|
+
2. **Examine relevant files** in the codebase to understand current state
|
|
20
|
+
3. **Create a structured plan** with:
|
|
21
|
+
- Executive Summary
|
|
22
|
+
- Current State Analysis
|
|
23
|
+
- Proposed Future State
|
|
24
|
+
- Implementation Phases (broken into sections)
|
|
25
|
+
- Detailed Tasks (actionable items with clear acceptance criteria)
|
|
26
|
+
- Risk Assessment and Mitigation Strategies
|
|
27
|
+
- Success Metrics
|
|
28
|
+
- Required Resources and Dependencies
|
|
29
|
+
|
|
30
|
+
4. **Task Breakdown Structure**:
|
|
31
|
+
- Each major section represents a phase or component
|
|
32
|
+
- Number and prioritize tasks within sections
|
|
33
|
+
- Include clear acceptance criteria for each task
|
|
34
|
+
- Specify dependencies between tasks
|
|
35
|
+
- Estimate effort levels (S/M/L/XL)
|
|
36
|
+
|
|
37
|
+
5. **Create task management structure**:
|
|
38
|
+
- Create directory: `dev/active/[task-name]/` (relative to project root)
|
|
39
|
+
- Generate three files:
|
|
40
|
+
- `[task-name]-plan.md` - The comprehensive plan
|
|
41
|
+
- `[task-name]-context.md` - Key files, decisions, dependencies
|
|
42
|
+
- `[task-name]-tasks.md` - Checklist format for tracking progress
|
|
43
|
+
- Include "Last Updated: YYYY-MM-DD" in each file
|
|
44
|
+
|
|
45
|
+
6. **Stop and Consult**: Pause and negotiate the plan with the user.
|
|
46
|
+
|
|
47
|
+
### Quality Standards
|
|
48
|
+
|
|
49
|
+
- Plans must be self-contained with all necessary context
|
|
50
|
+
- Use clear, actionable language
|
|
51
|
+
- Include specific technical details where relevant
|
|
52
|
+
- Consider both technical and business perspectives
|
|
53
|
+
- Account for potential risks and edge cases
|
|
54
|
+
|
|
55
|
+
## Update Development Documentation
|
|
56
|
+
|
|
57
|
+
When approaching context limits or before context reset:
|
|
58
|
+
|
|
59
|
+
### 1. Update Active Task Documentation
|
|
60
|
+
|
|
61
|
+
For each task in `/dev/active/`:
|
|
62
|
+
|
|
63
|
+
Update `[task-name]-context.md` with:
|
|
64
|
+
- Current implementation state
|
|
65
|
+
- Key decisions made this session
|
|
66
|
+
- Files modified and why
|
|
67
|
+
- Any blockers or issues discovered
|
|
68
|
+
- Next immediate steps
|
|
69
|
+
- Last Updated timestamp
|
|
70
|
+
|
|
71
|
+
Update `[task-name]-tasks.md` with:
|
|
72
|
+
- Mark completed tasks with checkmark
|
|
73
|
+
- Add any new tasks discovered
|
|
74
|
+
- Update in-progress tasks with current status
|
|
75
|
+
- Reorder priorities if needed
|
|
76
|
+
|
|
77
|
+
### 2. Capture Session Context
|
|
78
|
+
|
|
79
|
+
Include any relevant information about:
|
|
80
|
+
- Complex problems solved
|
|
81
|
+
- Architectural decisions made
|
|
82
|
+
- Tricky bugs found and fixed
|
|
83
|
+
- Integration points discovered
|
|
84
|
+
- Testing approaches used
|
|
85
|
+
- Performance optimizations made
|
|
86
|
+
|
|
87
|
+
### 3. Update Memory (if applicable)
|
|
88
|
+
|
|
89
|
+
- Store any new patterns or solutions in project memory/documentation
|
|
90
|
+
- Update entity relationships discovered
|
|
91
|
+
- Add observations about system behavior
|
|
92
|
+
|
|
93
|
+
### 4. Document Unfinished Work
|
|
94
|
+
|
|
95
|
+
- What was being worked on when context limit approached
|
|
96
|
+
- Exact state of any partially completed features
|
|
97
|
+
- Commands that need to be run on restart
|
|
98
|
+
- Any temporary workarounds that need permanent fixes
|
|
99
|
+
|
|
100
|
+
### 5. Create Handoff Notes
|
|
101
|
+
|
|
102
|
+
If switching to a new conversation:
|
|
103
|
+
- Exact file and line being edited
|
|
104
|
+
- The goal of current changes
|
|
105
|
+
- Any uncommitted changes that need attention
|
|
106
|
+
- Test commands to verify work
|
|
107
|
+
|
|
108
|
+
**Priority**: Focus on capturing information that would be hard to rediscover or reconstruct from code alone.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff
|
|
3
|
+
description: Write a HANDOFF.md file for another agent to continue the conversation. Use this skill when switching to a new conversation/session and need to pass context to the next agent. Triggers include "handoff", "write handoff", "create handoff", "pass to another agent".
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Write handoff document for agent continuation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Handoff
|
|
9
|
+
|
|
10
|
+
Write a HANDOFF.md file in the current working directory for another agent to continue this conversation.
|
|
11
|
+
|
|
12
|
+
Extract relevant context from the conversation to facilitate continuing this work. Write from the user's perspective (first person: "I did...", "I told you...").
|
|
13
|
+
|
|
14
|
+
## Consider What Would Be Useful
|
|
15
|
+
|
|
16
|
+
- What did the user just do or implement?
|
|
17
|
+
- What instructions did the user give that are still relevant (e.g., follow patterns in the codebase)?
|
|
18
|
+
- Did the user provide a plan or spec that should be included?
|
|
19
|
+
- What important information did the user share (certain libraries, patterns, constraints, preferences)?
|
|
20
|
+
- What key technical details were discovered (APIs, methods, patterns)?
|
|
21
|
+
- What caveats, limitations, or open questions remain?
|
|
22
|
+
|
|
23
|
+
Extract only what matters for the specific goal. Skip irrelevant questions. Choose an appropriate length based on the complexity.
|
|
24
|
+
|
|
25
|
+
Focus on capabilities and behavior, not file-by-file changes. Avoid excessive implementation details (variable names, storage keys, constants) unless critical.
|
|
26
|
+
|
|
27
|
+
## Format
|
|
28
|
+
|
|
29
|
+
- Plain text with bullets
|
|
30
|
+
- No markdown headers, no bold/italic, no code fences
|
|
31
|
+
- Use workspace-relative paths for files
|
|
32
|
+
- List relevant file or directory paths at the end:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
@src/project/main.py
|
|
36
|
+
@src/project/llm/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If the user's goal is unclear, ask for clarification.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jj-workspace
|
|
3
|
+
description: Create a jj workspace before starting work to enable parallel Claude sessions. Use this skill when starting a new task that should be isolated from other concurrent work. Triggers include "jj workspace", "parallel work", "create workspace", "isolated workspace".
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Create jj workspace for parallel work
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# JJ Workspace
|
|
9
|
+
|
|
10
|
+
Create a dedicated jj workspace before starting any task. This allows multiple Claude sessions to work in parallel without conflicts.
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Generate a short, descriptive workspace name based on the task (e.g., `workspace-add-login` or `workspace-fix-typo`)
|
|
15
|
+
2. Run `jj workspace add <workspace-name>` to create the workspace
|
|
16
|
+
3. Change into the workspace directory: `cd <workspace-name>`
|
|
17
|
+
4. Describe the change: `jj describe -m '<brief task description>'`
|
|
18
|
+
5. Continue all subsequent work within this workspace directory
|
|
19
|
+
|
|
20
|
+
If no task is provided, ask the user for a task description.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Create or update a skill
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Skill Creator
|
|
9
|
+
|
|
10
|
+
This skill provides guidance for creating effective skills.
|
|
11
|
+
|
|
12
|
+
## About Skills
|
|
13
|
+
|
|
14
|
+
Skills are modular, self-contained packages that extend the agent's capabilities by providing
|
|
15
|
+
specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific
|
|
16
|
+
domains or tasks - they transform the agent from a general-purpose assistant into a specialized
|
|
17
|
+
agent equipped with procedural knowledge.
|
|
18
|
+
|
|
19
|
+
### What Skills Provide
|
|
20
|
+
|
|
21
|
+
1. Specialized workflows - Multi-step procedures for specific domains
|
|
22
|
+
2. Tool integrations - Instructions for working with specific file formats or APIs
|
|
23
|
+
3. Domain expertise - Company-specific knowledge, schemas, business logic
|
|
24
|
+
4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks
|
|
25
|
+
|
|
26
|
+
## Core Principles
|
|
27
|
+
|
|
28
|
+
### Concise is Key
|
|
29
|
+
|
|
30
|
+
The context window is a public good. Skills share the context window with everything else:
|
|
31
|
+
system prompt, conversation history, other Skills' metadata, and the actual user request.
|
|
32
|
+
|
|
33
|
+
**Default assumption: The agent is already very smart.** Only add context the agent doesn't
|
|
34
|
+
already have. Challenge each piece of information: "Does the agent really need this explanation?"
|
|
35
|
+
and "Does this paragraph justify its token cost?"
|
|
36
|
+
|
|
37
|
+
Prefer concise examples over verbose explanations.
|
|
38
|
+
|
|
39
|
+
### Anatomy of a Skill
|
|
40
|
+
|
|
41
|
+
Every skill consists of a required SKILL.md file and optional bundled resources:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
skill-name/
|
|
45
|
+
├── SKILL.md (required)
|
|
46
|
+
│ ├── YAML frontmatter metadata (required)
|
|
47
|
+
│ │ ├── name: (required)
|
|
48
|
+
│ │ └── description: (required)
|
|
49
|
+
│ └── Markdown instructions (required)
|
|
50
|
+
└── Bundled Resources (optional)
|
|
51
|
+
├── scripts/ - Executable code (Python/Bash/etc.)
|
|
52
|
+
├── references/ - Documentation intended to be loaded into context as needed
|
|
53
|
+
└── assets/ - Files used in output (templates, icons, fonts, etc.)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### SKILL.md (required)
|
|
57
|
+
|
|
58
|
+
Every SKILL.md consists of:
|
|
59
|
+
|
|
60
|
+
- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields
|
|
61
|
+
that determine when the skill gets used, thus it is very important to be clear and comprehensive
|
|
62
|
+
in describing what the skill is, and when it should be used.
|
|
63
|
+
- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the
|
|
64
|
+
skill triggers (if at all).
|
|
65
|
+
|
|
66
|
+
#### Bundled Resources (optional)
|
|
67
|
+
|
|
68
|
+
##### Scripts (`scripts/`)
|
|
69
|
+
|
|
70
|
+
Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are
|
|
71
|
+
repeatedly rewritten.
|
|
72
|
+
|
|
73
|
+
- **When to include**: When the same code is being rewritten repeatedly or deterministic
|
|
74
|
+
reliability is needed
|
|
75
|
+
- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks
|
|
76
|
+
- **Benefits**: Token efficient, deterministic, may be executed without loading into context
|
|
77
|
+
|
|
78
|
+
##### References (`references/`)
|
|
79
|
+
|
|
80
|
+
Documentation and reference material intended to be loaded as needed into context.
|
|
81
|
+
|
|
82
|
+
- **When to include**: For documentation that the agent should reference while working
|
|
83
|
+
- **Examples**: `references/schema.md` for database schemas, `references/api_docs.md` for
|
|
84
|
+
API specifications
|
|
85
|
+
- **Benefits**: Keeps SKILL.md lean, loaded only when needed
|
|
86
|
+
|
|
87
|
+
##### Assets (`assets/`)
|
|
88
|
+
|
|
89
|
+
Files not intended to be loaded into context, but rather used within the output.
|
|
90
|
+
|
|
91
|
+
- **When to include**: When the skill needs files that will be used in the final output
|
|
92
|
+
- **Examples**: `assets/logo.png` for brand assets, `assets/template.html` for HTML templates
|
|
93
|
+
- **Benefits**: Separates output resources from documentation
|
|
94
|
+
|
|
95
|
+
## Skill Creation Process
|
|
96
|
+
|
|
97
|
+
Skill creation involves these steps:
|
|
98
|
+
|
|
99
|
+
1. Understand the skill with concrete examples
|
|
100
|
+
2. Plan reusable skill contents (scripts, references, assets)
|
|
101
|
+
3. Create the skill directory structure
|
|
102
|
+
4. Write SKILL.md with proper frontmatter
|
|
103
|
+
5. Add bundled resources as needed
|
|
104
|
+
6. Test and iterate based on real usage
|
|
105
|
+
|
|
106
|
+
### Skill Naming
|
|
107
|
+
|
|
108
|
+
- Use lowercase letters, digits, and hyphens only
|
|
109
|
+
- Prefer short, verb-led phrases that describe the action
|
|
110
|
+
- Name the skill folder exactly after the skill name
|
|
111
|
+
|
|
112
|
+
### Writing Guidelines
|
|
113
|
+
|
|
114
|
+
Always use imperative/infinitive form.
|
|
115
|
+
|
|
116
|
+
#### Frontmatter
|
|
117
|
+
|
|
118
|
+
Write the YAML frontmatter with `name` and `description`:
|
|
119
|
+
|
|
120
|
+
- `name`: The skill name (required)
|
|
121
|
+
- `description`: This is the primary triggering mechanism for your skill. Include both what
|
|
122
|
+
the Skill does and specific triggers/contexts for when to use it. Include all "when to use"
|
|
123
|
+
information here - Not in the body.
|
|
124
|
+
|
|
125
|
+
#### Body
|
|
126
|
+
|
|
127
|
+
Write instructions for using the skill and its bundled resources. Keep SKILL.md body to the
|
|
128
|
+
essentials and under 500 lines to minimize context bloat.
|
|
129
|
+
|
|
130
|
+
## Skill Storage Locations
|
|
131
|
+
|
|
132
|
+
Skills can be stored in multiple locations with the following priority (higher priority overrides lower):
|
|
133
|
+
|
|
134
|
+
| Priority | Scope | Path | Description |
|
|
135
|
+
|----------|---------|-----------------------------|-----------------------|
|
|
136
|
+
| 1 | Project | `.claude/skills/` | Current project only |
|
|
137
|
+
| 2 | User | `~/.klaude/skills/` | User-level |
|
|
138
|
+
| 3 | User | `~/.claude/skills/` | User-level (Claude) |
|
|
139
|
+
| 4 | System | `~/.klaude/skills/.system/` | Built-in system skills|
|
|
@@ -15,12 +15,22 @@ class Skill:
|
|
|
15
15
|
name: str # Skill identifier (lowercase-hyphen)
|
|
16
16
|
description: str # What the skill does and when to use it
|
|
17
17
|
content: str # Full markdown instructions
|
|
18
|
-
location: str # Skill location: 'user' or 'project'
|
|
18
|
+
location: str # Skill location: 'system', 'user', or 'project'
|
|
19
19
|
license: str | None = None
|
|
20
20
|
allowed_tools: list[str] | None = None
|
|
21
21
|
metadata: dict[str, str] | None = None
|
|
22
22
|
skill_path: Path | None = None
|
|
23
23
|
|
|
24
|
+
@property
|
|
25
|
+
def short_description(self) -> str:
|
|
26
|
+
"""Get short description for display in completions.
|
|
27
|
+
|
|
28
|
+
Returns metadata['short-description'] if available, otherwise falls back to description.
|
|
29
|
+
"""
|
|
30
|
+
if self.metadata and "short-description" in self.metadata:
|
|
31
|
+
return self.metadata["short-description"]
|
|
32
|
+
return self.description
|
|
33
|
+
|
|
24
34
|
def to_prompt(self) -> str:
|
|
25
35
|
"""Convert skill to prompt format for agent consumption"""
|
|
26
36
|
return f"""# Skill: {self.name}
|
|
@@ -36,13 +46,15 @@ class Skill:
|
|
|
36
46
|
class SkillLoader:
|
|
37
47
|
"""Load and manage Claude Skills from SKILL.md files"""
|
|
38
48
|
|
|
49
|
+
# System-level skills directory (built-in, lowest priority)
|
|
50
|
+
SYSTEM_SKILLS_DIR: ClassVar[Path] = Path("~/.klaude/skills/.system")
|
|
51
|
+
|
|
39
52
|
# User-level skills directories (checked in order, later ones override earlier ones with same name)
|
|
40
53
|
USER_SKILLS_DIRS: ClassVar[list[Path]] = [
|
|
41
54
|
Path("~/.claude/skills"),
|
|
42
55
|
Path("~/.klaude/skills"),
|
|
43
|
-
# Path("~/.claude/plugins/marketplaces"),
|
|
44
56
|
]
|
|
45
|
-
# Project-level skills directory
|
|
57
|
+
# Project-level skills directory (highest priority)
|
|
46
58
|
PROJECT_SKILLS_DIR: ClassVar[Path] = Path("./.claude/skills")
|
|
47
59
|
|
|
48
60
|
def __init__(self) -> None:
|
|
@@ -54,7 +66,7 @@ class SkillLoader:
|
|
|
54
66
|
|
|
55
67
|
Args:
|
|
56
68
|
skill_path: Path to SKILL.md file
|
|
57
|
-
location: Skill location ('user' or 'project')
|
|
69
|
+
location: Skill location ('system', 'user', or 'project')
|
|
58
70
|
|
|
59
71
|
Returns:
|
|
60
72
|
Skill object or None if loading failed
|
|
@@ -121,39 +133,57 @@ class SkillLoader:
|
|
|
121
133
|
return None
|
|
122
134
|
|
|
123
135
|
def discover_skills(self) -> list[Skill]:
|
|
124
|
-
"""Recursively find all SKILL.md files and load them from
|
|
136
|
+
"""Recursively find all SKILL.md files and load them from system, user and project directories.
|
|
137
|
+
|
|
138
|
+
Loading order (lower priority first, higher priority overrides):
|
|
139
|
+
1. System skills (~/.klaude/skills/.system/) - built-in, lowest priority
|
|
140
|
+
2. User skills (~/.claude/skills/, ~/.klaude/skills/) - user-level
|
|
141
|
+
3. Project skills (./.claude/skills/) - project-level, highest priority
|
|
125
142
|
|
|
126
143
|
Returns:
|
|
127
144
|
List of successfully loaded Skill objects
|
|
128
145
|
"""
|
|
129
146
|
skills: list[Skill] = []
|
|
130
147
|
|
|
131
|
-
# Load
|
|
148
|
+
# Load system-level skills first (lowest priority, can be overridden)
|
|
149
|
+
system_dir = self.SYSTEM_SKILLS_DIR.expanduser()
|
|
150
|
+
if system_dir.exists():
|
|
151
|
+
for skill_file in system_dir.rglob("SKILL.md"):
|
|
152
|
+
skill = self.load_skill(skill_file, location="system")
|
|
153
|
+
if skill:
|
|
154
|
+
skills.append(skill)
|
|
155
|
+
self.loaded_skills[skill.name] = skill
|
|
156
|
+
|
|
157
|
+
# Load user-level skills (override system skills if same name)
|
|
132
158
|
for user_dir in self.USER_SKILLS_DIRS:
|
|
133
159
|
expanded_dir = user_dir.expanduser()
|
|
134
160
|
if expanded_dir.exists():
|
|
135
|
-
for
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
161
|
+
for skill_file in expanded_dir.rglob("SKILL.md"):
|
|
162
|
+
# Skip files under .system directory (already loaded above)
|
|
163
|
+
if ".system" in skill_file.parts:
|
|
164
|
+
continue
|
|
165
|
+
skill = self.load_skill(skill_file, location="user")
|
|
166
|
+
if skill:
|
|
167
|
+
skills.append(skill)
|
|
168
|
+
self.loaded_skills[skill.name] = skill
|
|
141
169
|
|
|
142
170
|
# Load project-level skills (override user skills if same name)
|
|
143
171
|
project_dir = self.PROJECT_SKILLS_DIR.resolve()
|
|
144
172
|
if project_dir.exists():
|
|
145
|
-
for
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
self.loaded_skills[skill.name] = skill
|
|
173
|
+
for skill_file in project_dir.rglob("SKILL.md"):
|
|
174
|
+
skill = self.load_skill(skill_file, location="project")
|
|
175
|
+
if skill:
|
|
176
|
+
skills.append(skill)
|
|
177
|
+
self.loaded_skills[skill.name] = skill
|
|
151
178
|
|
|
152
179
|
# Log discovery summary
|
|
153
180
|
if skills:
|
|
181
|
+
system_count = sum(1 for s in skills if s.location == "system")
|
|
154
182
|
user_count = sum(1 for s in skills if s.location == "user")
|
|
155
183
|
project_count = sum(1 for s in skills if s.location == "project")
|
|
156
184
|
parts: list[str] = []
|
|
185
|
+
if system_count > 0:
|
|
186
|
+
parts.append(f"{system_count} system")
|
|
157
187
|
if user_count > 0:
|
|
158
188
|
parts.append(f"{user_count} user")
|
|
159
189
|
if project_count > 0:
|
|
@@ -171,11 +201,17 @@ class SkillLoader:
|
|
|
171
201
|
Returns:
|
|
172
202
|
Skill object or None if not found
|
|
173
203
|
"""
|
|
204
|
+
# Prefer exact match first (supports namespaced skill names).
|
|
205
|
+
skill = self.loaded_skills.get(name)
|
|
206
|
+
if skill is not None:
|
|
207
|
+
return skill
|
|
208
|
+
|
|
174
209
|
# Support both formats: 'pdf' and 'document-skills:pdf'
|
|
175
210
|
if ":" in name:
|
|
176
|
-
|
|
211
|
+
short = name.split(":")[-1]
|
|
212
|
+
return self.loaded_skills.get(short)
|
|
177
213
|
|
|
178
|
-
return
|
|
214
|
+
return None
|
|
179
215
|
|
|
180
216
|
def list_skills(self) -> list[str]:
|
|
181
217
|
"""Get list of all loaded skill names"""
|
|
@@ -224,25 +260,25 @@ class SkillLoader:
|
|
|
224
260
|
content = re.sub(dir_pattern, replace_dir_path, content)
|
|
225
261
|
|
|
226
262
|
# Pattern 2: Markdown links [text](./path or path)
|
|
227
|
-
# e.g., "[Guide](./docs/guide.md)" -> "[Guide](`/abs/path/to/docs/guide.md`) (use
|
|
263
|
+
# e.g., "[Guide](./docs/guide.md)" -> "[Guide](`/abs/path/to/docs/guide.md`) (use the Read tool to access)"
|
|
228
264
|
link_pattern = r"\[([^\]]+)\]\((\./)?([^\)]+\.md)\)"
|
|
229
265
|
|
|
230
266
|
def replace_link(match: re.Match[str]) -> str:
|
|
231
267
|
text = match.group(1)
|
|
232
268
|
filename = match.group(3)
|
|
233
269
|
abs_path = skill_dir / filename
|
|
234
|
-
return f"[{text}](`{abs_path}`) (use
|
|
270
|
+
return f"[{text}](`{abs_path}`) (use the Read tool to access)"
|
|
235
271
|
|
|
236
272
|
content = re.sub(link_pattern, replace_link, content)
|
|
237
273
|
|
|
238
274
|
# Pattern 3: Standalone markdown references
|
|
239
|
-
# e.g., "see reference.md" -> "see `/abs/path/to/reference.md` (use
|
|
275
|
+
# e.g., "see reference.md" -> "see `/abs/path/to/reference.md` (use the Read tool to access)"
|
|
240
276
|
standalone_pattern = r"(?<!\])\b(\w+\.md)\b(?!\))"
|
|
241
277
|
|
|
242
278
|
def replace_standalone(match: re.Match[str]) -> str:
|
|
243
279
|
filename = match.group(1)
|
|
244
280
|
abs_path = skill_dir / filename
|
|
245
|
-
return f"`{abs_path}` (use
|
|
281
|
+
return f"`{abs_path}` (use the Read tool to access)"
|
|
246
282
|
|
|
247
283
|
content = re.sub(standalone_pattern, replace_standalone, content)
|
|
248
284
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Global skill manager with lazy initialization.
|
|
2
|
+
|
|
3
|
+
This module provides a centralized interface for accessing skills throughout the application.
|
|
4
|
+
Skills are loaded lazily on first access to avoid unnecessary IO at startup.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from klaude_code.skill.loader import Skill, SkillLoader
|
|
8
|
+
from klaude_code.skill.system_skills import install_system_skills
|
|
9
|
+
|
|
10
|
+
_loader: SkillLoader | None = None
|
|
11
|
+
_initialized: bool = False
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _ensure_initialized() -> SkillLoader:
|
|
15
|
+
"""Ensure the skill system is initialized and return the loader."""
|
|
16
|
+
global _loader, _initialized
|
|
17
|
+
if not _initialized:
|
|
18
|
+
install_system_skills()
|
|
19
|
+
_loader = SkillLoader()
|
|
20
|
+
_loader.discover_skills()
|
|
21
|
+
_initialized = True
|
|
22
|
+
assert _loader is not None
|
|
23
|
+
return _loader
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_skill_loader() -> SkillLoader:
|
|
27
|
+
"""Get the global skill loader instance.
|
|
28
|
+
|
|
29
|
+
Lazily initializes the skill system on first call.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
The global SkillLoader instance
|
|
33
|
+
"""
|
|
34
|
+
return _ensure_initialized()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_skill(name: str) -> Skill | None:
|
|
38
|
+
"""Get a skill by name.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
name: Skill name (supports both 'skill-name' and 'namespace:skill-name')
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Skill object or None if not found
|
|
45
|
+
"""
|
|
46
|
+
return _ensure_initialized().get_skill(name)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_available_skills() -> list[tuple[str, str, str]]:
|
|
50
|
+
"""Get list of available skills for completion and display.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
List of (name, short_description, location) tuples.
|
|
54
|
+
Uses metadata['short-description'] if available, otherwise falls back to description.
|
|
55
|
+
Skills are ordered by priority: project > user > system.
|
|
56
|
+
"""
|
|
57
|
+
loader = _ensure_initialized()
|
|
58
|
+
skills = [(s.name, s.short_description, s.location) for s in loader.loaded_skills.values()]
|
|
59
|
+
location_order = {"project": 0, "user": 1, "system": 2}
|
|
60
|
+
skills.sort(key=lambda x: location_order.get(x[2], 3))
|
|
61
|
+
return skills
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def list_skill_names() -> list[str]:
|
|
65
|
+
"""Get list of all loaded skill names.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
List of skill names
|
|
69
|
+
"""
|
|
70
|
+
return _ensure_initialized().list_skills()
|