Skip to content

Commit 076761d

Browse files
committed
docs(specs): add spec for fixing bundled prompts directory resolution
- Fix prompts directory resolution for remote installation via uvx - Enable automatic detection of bundled prompts in installed packages - Maintain backward compatibility with custom prompts directories - Improve error messages for better user experience
1 parent 79045d8 commit 076761d

File tree

1 file changed

+342
-0
lines changed

1 file changed

+342
-0
lines changed
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# Specification: Fix Bundled Prompts Directory Resolution for Remote Installation
2+
3+
## Introduction/Overview
4+
5+
When users install and run `sdd-generate-commands` via `uvx` from a remote Git repository, the tool fails to locate the bundled `prompts` directory. This occurs because the `--prompts-dir` parameter defaults to `Path("prompts")` (a relative path), and the fallback logic in `_find_package_prompts_dir()` doesn't correctly resolve the installed package's prompts location.
6+
7+
**Current Error:**
8+
9+
```text
10+
Error: Prompts directory does not exist: prompts
11+
12+
To fix this:
13+
- Ensure the prompts directory exists
14+
- Check that --prompts-dir points to a valid directory (current: prompts)
15+
```
16+
17+
**Goal:** Enable seamless remote installation and execution via `uvx` by correctly resolving the bundled prompts directory, while maintaining backward compatibility for local development and custom prompts directories.
18+
19+
## Goals
20+
21+
1. **Primary Goal:** Fix the prompts directory resolution so `uvx --from git+https://github.com/...` works without requiring `--prompts-dir`
22+
2. **Maintain Backward Compatibility:** Ensure existing users with custom `--prompts-dir` paths continue to work unchanged
23+
3. **Support Development Mode:** Allow developers to use local prompts directories when working from source
24+
4. **Clear Error Messages:** When `--prompts-dir` is explicitly specified but doesn't exist, provide a clear error
25+
5. **Robust Solution:** Implement a comprehensive fix that handles both installed and development scenarios
26+
27+
## User Stories
28+
29+
### Story 1: Remote Installation User
30+
31+
**As a** new user installing via `uvx` from GitHub
32+
**I want to** run `uvx --from git+https://github.com/liatrio-labs/spec-driven-workflow@main sdd-generate-commands generate --agents windsurf`
33+
**So that** I can generate commands without needing to clone the repository or specify a prompts directory
34+
35+
**Acceptance Criteria:**
36+
37+
- Tool automatically finds bundled prompts in the installed package
38+
- No `--prompts-dir` argument required
39+
- Works from any directory (e.g., user's home directory)
40+
41+
### Story 2: Developer Using Local Source
42+
43+
**As a** developer working on the project
44+
**I want to** run `sdd-generate-commands generate` from the project root
45+
**So that** I can test changes to prompts without reinstalling the package
46+
47+
**Acceptance Criteria:**
48+
49+
- Tool finds `./prompts` directory when run from project root
50+
- Changes to prompt files are immediately reflected
51+
- No need to rebuild/reinstall for prompt changes
52+
53+
### Story 3: User with Custom Prompts
54+
55+
**As a** power user with custom prompts
56+
**I want to** specify `--prompts-dir /path/to/my/prompts`
57+
**So that** I can use my own prompt templates
58+
59+
**Acceptance Criteria:**
60+
61+
- Custom path is respected when specified
62+
- Clear error if specified path doesn't exist
63+
- No fallback to bundled prompts when custom path is explicitly provided
64+
65+
## Demoable Units of Work
66+
67+
### Unit 1: Fix Default Prompts Directory Resolution
68+
69+
**Purpose:** Enable automatic detection of bundled prompts for installed packages
70+
**Users:** Remote installation users (uvx, pip)
71+
72+
**Demo Criteria:**
73+
74+
- Run from home directory: `uvx --from git+https://github.com/liatrio-labs/spec-driven-workflow@BRANCH sdd-generate-commands generate --agents windsurf --dry-run`
75+
- Command succeeds and shows prompts loaded
76+
- No error about missing prompts directory
77+
78+
**Proof Artifacts:**
79+
80+
- Terminal output showing successful execution
81+
- Output includes: `Prompts loaded: N` (where N > 0)
82+
- No error messages about missing directories
83+
84+
### Unit 2: Validate Custom Prompts Directory Behavior
85+
86+
**Purpose:** Ensure explicit `--prompts-dir` works correctly with validation
87+
**Users:** Power users with custom prompts
88+
89+
**Demo Criteria:**
90+
91+
1. Run with valid custom directory: `sdd-generate-commands generate --prompts-dir /tmp/my-prompts --agents cursor --dry-run`
92+
- Should succeed if directory exists with .md files
93+
2. Run with invalid custom directory: `sdd-generate-commands generate --prompts-dir /nonexistent --agents cursor`
94+
- Should fail with clear error message
95+
- Should NOT fall back to bundled prompts
96+
97+
**Proof Artifacts:**
98+
99+
- Terminal output for both scenarios
100+
- Error message clearly states the specified directory doesn't exist
101+
- No fallback behavior when path is explicitly provided
102+
103+
### Unit 3: Verify Development Workflow
104+
105+
**Purpose:** Ensure local development continues to work seamlessly
106+
**Users:** Project contributors and developers
107+
108+
**Demo Criteria:**
109+
110+
- From project root: `sdd-generate-commands generate --agents cursor --dry-run`
111+
- Prompts loaded from `./prompts` directory
112+
- Changes to `./prompts/*.md` are immediately reflected
113+
114+
**Proof Artifacts:**
115+
116+
- Terminal output showing prompts loaded from local directory
117+
- Test run showing modified prompt content is used
118+
119+
## Functional Requirements
120+
121+
### FR1: Default Prompts Directory Resolution
122+
123+
When `--prompts-dir` is NOT specified (uses default `Path("prompts")`), the tool MUST:
124+
125+
1. First check if `./prompts` exists relative to current working directory
126+
2. If not found, attempt to locate bundled prompts using `_find_package_prompts_dir()`
127+
3. Use the first valid prompts directory found
128+
4. Raise a clear error if no valid prompts directory is found
129+
130+
### FR2: Explicit Prompts Directory Validation
131+
132+
When `--prompts-dir` IS specified by the user, the tool MUST:
133+
134+
1. Use ONLY the specified path (no fallback to bundled prompts)
135+
2. Raise a clear error if the specified directory doesn't exist
136+
3. Raise a clear error if the specified directory exists but contains no `.md` files
137+
138+
### FR3: Package Prompts Directory Detection
139+
140+
The `_find_package_prompts_dir()` function MUST:
141+
142+
1. Correctly locate the prompts directory in installed packages (uvx, pip, wheel)
143+
2. Handle both development installs (`pip install -e .`) and production installs
144+
3. Return `None` if prompts directory cannot be found (not raise an exception)
145+
4. Work regardless of the current working directory
146+
147+
### FR4: Error Messages
148+
149+
Error messages MUST:
150+
151+
1. Clearly distinguish between "default path not found" vs "specified path not found"
152+
2. Provide actionable guidance for resolution
153+
3. Indicate whether fallback was attempted
154+
4. Show the actual path that was checked
155+
156+
### FR5: Backward Compatibility
157+
158+
The fix MUST:
159+
160+
1. Not break existing workflows that use `--prompts-dir` with valid paths
161+
2. Not change the CLI interface or parameter names
162+
3. Not require changes to `pyproject.toml` build configuration (prompts already bundled)
163+
4. Maintain the same behavior for local development (running from project root)
164+
165+
## Non-Goals (Out of Scope)
166+
167+
1. **Dynamic Prompt Downloads:** Not downloading prompts from GitHub at runtime
168+
2. **Prompt Caching:** Not implementing local caching of downloaded prompts
169+
3. **Multiple Prompts Directories:** Not supporting multiple prompts directories simultaneously
170+
4. **Prompt Versioning:** Not implementing version-specific prompt selection
171+
5. **Other Installation Methods:** Only focusing on `uvx` (pip support is a side effect)
172+
6. **Configuration Files:** Not adding config file support for default prompts directory
173+
174+
## Design Considerations
175+
176+
### Current Implementation Analysis
177+
178+
**File:** `slash_commands/writer.py`
179+
180+
**Current `_find_package_prompts_dir()` implementation:**
181+
182+
```python
183+
def _find_package_prompts_dir() -> Path | None:
184+
"""Find the prompts directory in the installed package."""
185+
# Goes up from writer.py to package root
186+
package_root = Path(__file__).parent.parent
187+
prompts_dir = package_root / "prompts"
188+
189+
if prompts_dir.exists():
190+
return prompts_dir
191+
192+
return None
193+
```
194+
195+
**Issue:** When installed via uvx/pip, `Path(__file__).parent.parent` may not correctly resolve to the package root where prompts are bundled.
196+
197+
### Proposed Solution
198+
199+
1. **Update `_find_package_prompts_dir()`** to use multiple strategies:
200+
- Strategy 1: Check relative to `__file__` (current approach)
201+
- Strategy 2: Use `importlib.resources` to locate bundled data
202+
- Strategy 3: Check site-packages installation path
203+
204+
2. **Update `_load_prompts()` logic** to:
205+
- Distinguish between "default path" and "user-specified path"
206+
- Only attempt fallback for default path
207+
- Provide different error messages for each case
208+
209+
3. **Update CLI default** to use a sentinel value or None to detect when user hasn't specified a path
210+
211+
### Alternative Approaches Considered
212+
213+
#### Alternative 1: Change CLI default to None
214+
215+
- Pros: Clear distinction between default and user-specified
216+
- Cons: Requires more complex logic in CLI layer
217+
218+
#### Alternative 2: Use importlib.resources exclusively
219+
220+
- Pros: Standard library approach for package data
221+
- Cons: Requires Python 3.9+ (we're on 3.12+, so this is fine)
222+
223+
#### Alternative 3: Environment variable for prompts path
224+
225+
- Pros: Flexible for different environments
226+
- Cons: Adds complexity, not addressing root cause
227+
228+
**Recommended:** Combination of Alternative 1 and Alternative 2
229+
230+
## Technical Considerations
231+
232+
### Package Structure (from pyproject.toml)
233+
234+
```toml
235+
[tool.hatch.build.targets.wheel.force-include]
236+
"prompts/" = "prompts/"
237+
```
238+
239+
The prompts directory is already being bundled at the package root level.
240+
241+
### Installation Paths
242+
243+
- **uvx:** `~/.local/share/uv/cache/...` or similar
244+
- **pip:** `site-packages/` in virtual environment or system Python
245+
- **Development:** Project root directory
246+
247+
### Python Version
248+
249+
- Requires Python 3.12+ (already specified in `pyproject.toml`)
250+
- Can use `importlib.resources.files()` (available in 3.9+)
251+
252+
### Dependencies
253+
254+
- No new dependencies required
255+
- Use standard library `importlib.resources`
256+
257+
## Success Metrics
258+
259+
1. **Installation Success Rate:** 100% of remote installations via uvx succeed without errors
260+
2. **Zero Breaking Changes:** All existing tests pass without modification
261+
3. **Error Clarity:** User feedback indicates error messages are clear and actionable
262+
4. **Development Workflow:** No additional steps required for local development
263+
264+
## Open Questions
265+
266+
None - all requirements are clear based on user responses.
267+
268+
## Implementation Notes
269+
270+
### Files to Modify
271+
272+
1. **`slash_commands/writer.py`**
273+
- Update `_find_package_prompts_dir()` to use `importlib.resources`
274+
- Update `_load_prompts()` to handle default vs explicit paths differently
275+
- Improve error messages
276+
277+
2. **`slash_commands/cli.py`**
278+
- Change `prompts_dir` default from `Path("prompts")` to `None`
279+
- Pass information about whether path was user-specified to `SlashCommandWriter`
280+
281+
3. **Tests to Update/Add**
282+
- `tests/test_writer.py`: Update existing tests for new behavior
283+
- Add test for `importlib.resources` fallback
284+
- Add test for explicit path validation
285+
- Add test for error message clarity
286+
287+
### Key Code Changes
288+
289+
**In `cli.py`:**
290+
291+
```python
292+
prompts_dir: Annotated[
293+
Path | None, # Changed from Path
294+
typer.Option(
295+
"--prompts-dir",
296+
"-p",
297+
help="Directory containing prompt files",
298+
),
299+
] = None, # Changed from Path("prompts")
300+
```
301+
302+
**In `writer.py`:**
303+
304+
```python
305+
def _find_package_prompts_dir() -> Path | None:
306+
"""Find the prompts directory in the installed package."""
307+
# Try importlib.resources first
308+
try:
309+
from importlib.resources import files
310+
package_files = files("spec_driven_development_mcp")
311+
prompts_dir = package_files / "prompts"
312+
if prompts_dir.is_dir():
313+
return Path(str(prompts_dir))
314+
except (ImportError, TypeError, FileNotFoundError):
315+
pass
316+
317+
# Fallback to relative path from __file__
318+
package_root = Path(__file__).parent.parent
319+
prompts_dir = package_root / "prompts"
320+
if prompts_dir.exists():
321+
return prompts_dir
322+
323+
return None
324+
```
325+
326+
### Testing Strategy
327+
328+
1. **Unit Tests:** Test each resolution strategy independently
329+
2. **Integration Tests:** Test full CLI flow with different installation scenarios
330+
3. **Manual Testing:** Verify uvx installation from GitHub works
331+
4. **Regression Testing:** Ensure all existing tests pass
332+
333+
## Definition of Done
334+
335+
- [ ] Code changes implemented and reviewed
336+
- [ ] All existing tests pass
337+
- [ ] New tests added for new behavior
338+
- [ ] Manual testing confirms uvx installation works
339+
- [ ] Error messages are clear and actionable
340+
- [ ] Documentation updated (if needed)
341+
- [ ] No breaking changes to existing workflows
342+
- [ ] PR approved and merged

0 commit comments

Comments
 (0)