zipsa 0.1.0__tar.gz
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.
- zipsa-0.1.0/.gitignore +9 -0
- zipsa-0.1.0/CLAUDE.md +336 -0
- zipsa-0.1.0/PKG-INFO +81 -0
- zipsa-0.1.0/README.md +56 -0
- zipsa-0.1.0/docs/plans/2026-05-04-run-logging.md +1103 -0
- zipsa-0.1.0/docs/research-notes-run-logging.md +278 -0
- zipsa-0.1.0/docs/run-logging.md +228 -0
- zipsa-0.1.0/docs/specs/2026-05-04-run-logging-design.md +363 -0
- zipsa-0.1.0/pyproject.toml +65 -0
- zipsa-0.1.0/runtime-config.yaml.example +20 -0
- zipsa-0.1.0/tests/__init__.py +1 -0
- zipsa-0.1.0/tests/fixtures/manifests/SKILL.md +3 -0
- zipsa-0.1.0/tests/fixtures/manifests/minimal.yaml +8 -0
- zipsa-0.1.0/tests/fixtures/manifests/with-mcp.yaml +28 -0
- zipsa-0.1.0/tests/fixtures/skills/test-skill/SKILL.md +7 -0
- zipsa-0.1.0/tests/fixtures/skills/test-skill/manifest.yaml +13 -0
- zipsa-0.1.0/tests/test_cli.py +219 -0
- zipsa-0.1.0/tests/test_executor.py +311 -0
- zipsa-0.1.0/tests/test_limits.py +190 -0
- zipsa-0.1.0/tests/test_models.py +177 -0
- zipsa-0.1.0/tests/test_run_logger.py +246 -0
- zipsa-0.1.0/tests/test_runtimes.py +92 -0
- zipsa-0.1.0/tests/test_skill.py +346 -0
- zipsa-0.1.0/uv.lock +788 -0
- zipsa-0.1.0/zipsa/__init__.py +3 -0
- zipsa-0.1.0/zipsa/cli.py +346 -0
- zipsa-0.1.0/zipsa/core/__init__.py +1 -0
- zipsa-0.1.0/zipsa/core/executor.py +591 -0
- zipsa-0.1.0/zipsa/core/models.py +97 -0
- zipsa-0.1.0/zipsa/core/skill.py +190 -0
- zipsa-0.1.0/zipsa/runtimes/__init__.py +33 -0
- zipsa-0.1.0/zipsa/runtimes/base.py +67 -0
- zipsa-0.1.0/zipsa/runtimes/claude.py +66 -0
zipsa-0.1.0/.gitignore
ADDED
zipsa-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# Launcher Development Guide
|
|
2
|
+
|
|
3
|
+
> **IMPORTANT:** Read [/CLAUDE.md](../CLAUDE.md) first for common development rules.
|
|
4
|
+
|
|
5
|
+
This guide covers Launcher-specific development practices.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Project Purpose
|
|
10
|
+
|
|
11
|
+
Python CLI tool for orchestrating SKILL execution across multiple runtimes (Claude Code, Codex, Gemini).
|
|
12
|
+
|
|
13
|
+
**Goals:**
|
|
14
|
+
- Runtime-agnostic execution
|
|
15
|
+
- Manifest validation
|
|
16
|
+
- Environment variable management
|
|
17
|
+
- Execution logging and metrics
|
|
18
|
+
|
|
19
|
+
## Technology Stack
|
|
20
|
+
- **Language:** Python 3.12+
|
|
21
|
+
- **Package Manager:** uv
|
|
22
|
+
- **Testing:** pytest with coverage
|
|
23
|
+
- **Validation:** Pydantic models
|
|
24
|
+
- **CLI:** Click framework
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## TDD for Python
|
|
29
|
+
|
|
30
|
+
**Example TDD cycle with pytest:**
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# 1. Write test
|
|
34
|
+
# tests/test_new_feature.py
|
|
35
|
+
|
|
36
|
+
# 2. Run test (should fail)
|
|
37
|
+
uv run pytest tests/test_new_feature.py -v
|
|
38
|
+
|
|
39
|
+
# 3. Implement feature
|
|
40
|
+
# zipsa/core/new_feature.py
|
|
41
|
+
|
|
42
|
+
# 4. Run test (should pass)
|
|
43
|
+
uv run pytest tests/test_new_feature.py -v
|
|
44
|
+
|
|
45
|
+
# 5. Run all tests
|
|
46
|
+
uv run pytest --cov=zipsa
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Coverage Requirements:**
|
|
50
|
+
- Minimum: 70% overall coverage
|
|
51
|
+
- New code: 80%+ coverage preferred
|
|
52
|
+
- Don't sacrifice test quality for coverage %
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Code Guidelines
|
|
57
|
+
|
|
58
|
+
### Project Structure
|
|
59
|
+
```
|
|
60
|
+
launcher/
|
|
61
|
+
├── zipsa/ # Main package
|
|
62
|
+
│ ├── __init__.py
|
|
63
|
+
│ ├── cli.py # Click commands
|
|
64
|
+
│ ├── core/ # Core logic
|
|
65
|
+
│ │ ├── executor.py # Docker orchestration
|
|
66
|
+
│ │ ├── skill.py # Skill loading
|
|
67
|
+
│ │ └── models.py # Pydantic models
|
|
68
|
+
│ └── runtimes/ # Runtime plugins
|
|
69
|
+
│ ├── base.py
|
|
70
|
+
│ ├── claude.py
|
|
71
|
+
│ └── ...
|
|
72
|
+
├── tests/ # Test files
|
|
73
|
+
│ ├── test_cli.py
|
|
74
|
+
│ ├── test_executor.py
|
|
75
|
+
│ └── fixtures/ # Test data
|
|
76
|
+
└── pyproject.toml
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Pydantic Models
|
|
80
|
+
Use Pydantic for all configuration and validation:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from pydantic import BaseModel, Field
|
|
84
|
+
|
|
85
|
+
class SkillMetadata(BaseModel):
|
|
86
|
+
"""Skill metadata with validation."""
|
|
87
|
+
name: str
|
|
88
|
+
version: str
|
|
89
|
+
author: str | None = None
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Error Handling
|
|
93
|
+
```python
|
|
94
|
+
# Good - specific exceptions
|
|
95
|
+
try:
|
|
96
|
+
skill = Skill.load(path)
|
|
97
|
+
except FileNotFoundError:
|
|
98
|
+
print(f"Error: Manifest not found: {path}")
|
|
99
|
+
sys.exit(1)
|
|
100
|
+
|
|
101
|
+
# Bad - generic exceptions
|
|
102
|
+
try:
|
|
103
|
+
skill = Skill.load(path)
|
|
104
|
+
except Exception as e:
|
|
105
|
+
print(f"Error: {e}")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Testing Strategy
|
|
111
|
+
|
|
112
|
+
### Running Tests
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Run all tests
|
|
116
|
+
uv run pytest
|
|
117
|
+
|
|
118
|
+
# Run specific test file
|
|
119
|
+
uv run pytest tests/test_executor.py -v
|
|
120
|
+
|
|
121
|
+
# Run with coverage
|
|
122
|
+
uv run pytest --cov=zipsa --cov-report=term-missing
|
|
123
|
+
|
|
124
|
+
# Run only failed tests
|
|
125
|
+
uv run pytest --lf
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Test Structure
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
class TestFeatureName:
|
|
132
|
+
"""Test suite for feature."""
|
|
133
|
+
|
|
134
|
+
def test_basic_behavior(self):
|
|
135
|
+
"""Test basic expected behavior."""
|
|
136
|
+
result = function(input)
|
|
137
|
+
assert result == expected
|
|
138
|
+
|
|
139
|
+
def test_edge_case(self):
|
|
140
|
+
"""Test edge case handling."""
|
|
141
|
+
with pytest.raises(ValueError):
|
|
142
|
+
function(invalid_input)
|
|
143
|
+
|
|
144
|
+
def test_with_fixture(self, tmp_path):
|
|
145
|
+
"""Test using pytest fixture."""
|
|
146
|
+
file_path = tmp_path / "test.yaml"
|
|
147
|
+
# ... test implementation
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Coverage Requirements
|
|
151
|
+
- Minimum: 70% overall coverage
|
|
152
|
+
- New code: 80%+ coverage preferred
|
|
153
|
+
- Don't sacrifice test quality for coverage %
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Quality Checklist
|
|
158
|
+
|
|
159
|
+
**Launcher-specific checks** (see [/CLAUDE.md](../CLAUDE.md) for common checks):
|
|
160
|
+
|
|
161
|
+
- [ ] All tests pass: `uv run pytest`
|
|
162
|
+
- [ ] Coverage ≥ 70%: `uv run pytest --cov=zipsa`
|
|
163
|
+
- [ ] No linting errors (if configured)
|
|
164
|
+
- [ ] Pydantic models validate correctly
|
|
165
|
+
- [ ] CLI commands work as expected
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Common Tasks
|
|
170
|
+
|
|
171
|
+
### Adding a New Runtime
|
|
172
|
+
|
|
173
|
+
1. Create runtime plugin:
|
|
174
|
+
```python
|
|
175
|
+
# zipsa/runtimes/newruntime.py
|
|
176
|
+
from .base import RuntimeBase
|
|
177
|
+
|
|
178
|
+
class NewRuntime(RuntimeBase):
|
|
179
|
+
name = "newruntime"
|
|
180
|
+
# ... implement methods
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
2. Register in `runtimes/__init__.py`
|
|
184
|
+
|
|
185
|
+
3. Write tests:
|
|
186
|
+
```python
|
|
187
|
+
# tests/test_runtimes.py
|
|
188
|
+
class TestNewRuntime:
|
|
189
|
+
def test_runtime_name(self):
|
|
190
|
+
runtime = NewRuntime()
|
|
191
|
+
assert runtime.name == "newruntime"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Adding a New CLI Command
|
|
195
|
+
|
|
196
|
+
1. Add command in `cli.py`:
|
|
197
|
+
```python
|
|
198
|
+
@click.command()
|
|
199
|
+
def mycommand():
|
|
200
|
+
"""Description of command."""
|
|
201
|
+
# implementation
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
2. Add to CLI group
|
|
205
|
+
|
|
206
|
+
3. Write tests:
|
|
207
|
+
```python
|
|
208
|
+
# tests/test_cli.py
|
|
209
|
+
def test_mycommand():
|
|
210
|
+
result = runner.invoke(cli, ["mycommand"])
|
|
211
|
+
assert result.exit_code == 0
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Updating Pydantic Models
|
|
215
|
+
|
|
216
|
+
1. Write test with new field:
|
|
217
|
+
```python
|
|
218
|
+
def test_new_field():
|
|
219
|
+
data = {"name": "test", "new_field": "value"}
|
|
220
|
+
model = MyModel.model_validate(data)
|
|
221
|
+
assert model.new_field == "value"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
2. Update model:
|
|
225
|
+
```python
|
|
226
|
+
class MyModel(BaseModel):
|
|
227
|
+
name: str
|
|
228
|
+
new_field: str | None = None
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
3. Verify tests pass
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Development Commands
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Install dependencies
|
|
239
|
+
uv pip install -e ".[dev]"
|
|
240
|
+
|
|
241
|
+
# Run tests
|
|
242
|
+
uv run pytest
|
|
243
|
+
|
|
244
|
+
# Run with coverage
|
|
245
|
+
uv run pytest --cov=zipsa --cov-report=html
|
|
246
|
+
open htmlcov/index.html
|
|
247
|
+
|
|
248
|
+
# Format code (if configured)
|
|
249
|
+
uv run black zipsa/ tests/
|
|
250
|
+
|
|
251
|
+
# Type checking (if configured)
|
|
252
|
+
uv run mypy zipsa/
|
|
253
|
+
|
|
254
|
+
# Interactive Python with package
|
|
255
|
+
uv run python
|
|
256
|
+
>>> from zipsa.core.skill import Skill
|
|
257
|
+
>>> skill = Skill.load("../skills/daily-progress")
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Debugging Tips
|
|
263
|
+
|
|
264
|
+
### Dry Run Mode
|
|
265
|
+
```bash
|
|
266
|
+
# See what Docker command would be executed
|
|
267
|
+
zipsa run my-skill "query" --dry-run
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Interactive Shell in Container
|
|
271
|
+
```bash
|
|
272
|
+
# Debug inside container
|
|
273
|
+
zipsa shell ../skills/daily-progress
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Test Specific Scenario
|
|
277
|
+
```bash
|
|
278
|
+
# Run single test with verbose output
|
|
279
|
+
uv run pytest tests/test_executor.py::TestRuntimeConfig::test_auto_inject_env_from_config -vv
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Check Logs
|
|
283
|
+
```bash
|
|
284
|
+
# Execution logs are saved in skill directory
|
|
285
|
+
cat ../skills/daily-progress/.zipsa/runs/*/output.jsonl
|
|
286
|
+
cat ../skills/daily-progress/.zipsa/runs/*/metadata.json
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Troubleshooting
|
|
292
|
+
|
|
293
|
+
### Issue: Tests failing with import errors
|
|
294
|
+
|
|
295
|
+
**Solution:**
|
|
296
|
+
```bash
|
|
297
|
+
# Reinstall in development mode
|
|
298
|
+
uv pip install -e ".[dev]"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Issue: Coverage too low
|
|
302
|
+
|
|
303
|
+
**Solution:**
|
|
304
|
+
- Focus on critical paths first
|
|
305
|
+
- Add tests for error cases
|
|
306
|
+
- Don't skip integration tests
|
|
307
|
+
|
|
308
|
+
### Issue: Pydantic validation error
|
|
309
|
+
|
|
310
|
+
**Solution:**
|
|
311
|
+
```bash
|
|
312
|
+
# Check model definition matches test data
|
|
313
|
+
# Use .model_validate() not direct instantiation
|
|
314
|
+
data = {"field": "value"}
|
|
315
|
+
model = MyModel.model_validate(data) # Good
|
|
316
|
+
model = MyModel(field="value") # Also works but less explicit
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Resources
|
|
322
|
+
|
|
323
|
+
- **Python Docs:** https://docs.python.org/3.12/
|
|
324
|
+
- **Pydantic:** https://docs.pydantic.dev/
|
|
325
|
+
- **pytest:** https://docs.pytest.org/
|
|
326
|
+
- **Click:** https://click.palletsprojects.com/
|
|
327
|
+
- **uv:** https://github.com/astral-sh/uv
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Notes
|
|
332
|
+
|
|
333
|
+
- This is a **CLI orchestrator**, not a runtime environment
|
|
334
|
+
- Focus on clean interfaces and testability
|
|
335
|
+
- Keep Docker logic isolated in executor
|
|
336
|
+
- Runtime plugins should be minimal and focused
|
zipsa-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zipsa
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multi-runtime skill launcher for Claude Code, Codex, and Gemini CLI
|
|
5
|
+
Author-email: WestbrookAI <neochoon@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: agent,claude,codex,gemini,mcp,runtime
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: typer>=0.9
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Zipsa Launcher
|
|
27
|
+
|
|
28
|
+
Multi-runtime skill launcher for Claude Code, Codex, and Gemini CLI.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e ".[dev]"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
### Runtime Configuration
|
|
39
|
+
|
|
40
|
+
Create `~/.zipsa/runtime-config.yaml` to configure runtime-specific settings:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
runtimes:
|
|
44
|
+
claude:
|
|
45
|
+
auto_inject_env:
|
|
46
|
+
- CLAUDE_CODE_OAUTH_TOKEN
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**How it works:**
|
|
50
|
+
- Only environment variables listed in `auto_inject_env` are automatically passed to the container
|
|
51
|
+
- If the config file doesn't exist or a runtime is not configured, no auto-injection occurs
|
|
52
|
+
- User-provided environment variables (via CLI) always take precedence
|
|
53
|
+
- If a listed env var is not set in the host environment, a warning is shown
|
|
54
|
+
|
|
55
|
+
Example file is provided at `runtime-config.yaml.example`.
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Run a skill
|
|
61
|
+
zipsa run weather "Seoul weather"
|
|
62
|
+
|
|
63
|
+
# With specific runtime
|
|
64
|
+
zipsa run weather "Seoul" --runtime claude
|
|
65
|
+
|
|
66
|
+
# With environment variables (overrides auto-inject)
|
|
67
|
+
zipsa run weather "Seoul" --env CLAUDE_CODE_OAUTH_TOKEN=custom-token
|
|
68
|
+
|
|
69
|
+
# Validate manifest
|
|
70
|
+
zipsa validate ../zipsa-skills/weather
|
|
71
|
+
|
|
72
|
+
# List skills
|
|
73
|
+
zipsa list ../zipsa-skills
|
|
74
|
+
|
|
75
|
+
# List runtimes
|
|
76
|
+
zipsa runtimes
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Development
|
|
80
|
+
|
|
81
|
+
See [Design Document](../docs/zipsa-python-design.md) for architecture details.
|
zipsa-0.1.0/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Zipsa Launcher
|
|
2
|
+
|
|
3
|
+
Multi-runtime skill launcher for Claude Code, Codex, and Gemini CLI.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e ".[dev]"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
### Runtime Configuration
|
|
14
|
+
|
|
15
|
+
Create `~/.zipsa/runtime-config.yaml` to configure runtime-specific settings:
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
runtimes:
|
|
19
|
+
claude:
|
|
20
|
+
auto_inject_env:
|
|
21
|
+
- CLAUDE_CODE_OAUTH_TOKEN
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**How it works:**
|
|
25
|
+
- Only environment variables listed in `auto_inject_env` are automatically passed to the container
|
|
26
|
+
- If the config file doesn't exist or a runtime is not configured, no auto-injection occurs
|
|
27
|
+
- User-provided environment variables (via CLI) always take precedence
|
|
28
|
+
- If a listed env var is not set in the host environment, a warning is shown
|
|
29
|
+
|
|
30
|
+
Example file is provided at `runtime-config.yaml.example`.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Run a skill
|
|
36
|
+
zipsa run weather "Seoul weather"
|
|
37
|
+
|
|
38
|
+
# With specific runtime
|
|
39
|
+
zipsa run weather "Seoul" --runtime claude
|
|
40
|
+
|
|
41
|
+
# With environment variables (overrides auto-inject)
|
|
42
|
+
zipsa run weather "Seoul" --env CLAUDE_CODE_OAUTH_TOKEN=custom-token
|
|
43
|
+
|
|
44
|
+
# Validate manifest
|
|
45
|
+
zipsa validate ../zipsa-skills/weather
|
|
46
|
+
|
|
47
|
+
# List skills
|
|
48
|
+
zipsa list ../zipsa-skills
|
|
49
|
+
|
|
50
|
+
# List runtimes
|
|
51
|
+
zipsa runtimes
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Development
|
|
55
|
+
|
|
56
|
+
See [Design Document](../docs/zipsa-python-design.md) for architecture details.
|