pyskillet 0.0.1__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.
- pyskillet-0.0.1/.claude/.gitignore +2 -0
- pyskillet-0.0.1/.claude/CLAUDE.md +36 -0
- pyskillet-0.0.1/.claude-template/commands/skillet/add.md +55 -0
- pyskillet-0.0.1/.github/dependabot.yml +15 -0
- pyskillet-0.0.1/.github/workflows/build.yml +31 -0
- pyskillet-0.0.1/.github/workflows/changelog.yml +31 -0
- pyskillet-0.0.1/.github/workflows/docs.yml +35 -0
- pyskillet-0.0.1/.github/workflows/integration.yml +33 -0
- pyskillet-0.0.1/.github/workflows/lint.yml +34 -0
- pyskillet-0.0.1/.github/workflows/pr-monitor.yml +17 -0
- pyskillet-0.0.1/.github/workflows/release.yml +94 -0
- pyskillet-0.0.1/.github/workflows/security.yml +29 -0
- pyskillet-0.0.1/.github/workflows/test.yml +44 -0
- pyskillet-0.0.1/.github/workflows/typecheck.yml +29 -0
- pyskillet-0.0.1/.github/workflows/version-bump.yml +97 -0
- pyskillet-0.0.1/.gitignore +22 -0
- pyskillet-0.0.1/.pre-commit-config.yaml +9 -0
- pyskillet-0.0.1/.python-version +1 -0
- pyskillet-0.0.1/CHANGELOG.md +44 -0
- pyskillet-0.0.1/LICENSE +21 -0
- pyskillet-0.0.1/PKG-INFO +149 -0
- pyskillet-0.0.1/README.md +126 -0
- pyskillet-0.0.1/ROADMAP.md +61 -0
- pyskillet-0.0.1/docs/.gitignore +3 -0
- pyskillet-0.0.1/docs/.vitepress/config.ts +26 -0
- pyskillet-0.0.1/docs/getting-started.md +11 -0
- pyskillet-0.0.1/docs/index.md +23 -0
- pyskillet-0.0.1/docs/netlify.toml +11 -0
- pyskillet-0.0.1/docs/package.json +13 -0
- pyskillet-0.0.1/docs/pnpm-lock.yaml +1448 -0
- pyskillet-0.0.1/evals/add-command/001.yaml +4 -0
- pyskillet-0.0.1/evals/add-command/002.yaml +4 -0
- pyskillet-0.0.1/evals/add-command/003.yaml +4 -0
- pyskillet-0.0.1/evals/add-command/004.yaml +7 -0
- pyskillet-0.0.1/evals/add-command/005.yaml +6 -0
- pyskillet-0.0.1/evals/add-command/006.yaml +9 -0
- pyskillet-0.0.1/evals/add-command/007.yaml +8 -0
- pyskillet-0.0.1/evals/add-command/008.yaml +8 -0
- pyskillet-0.0.1/evals/add-command/009.yaml +10 -0
- pyskillet-0.0.1/evals/add-command/010.yaml +10 -0
- pyskillet-0.0.1/evals/add-command/011.yaml +10 -0
- pyskillet-0.0.1/evals/add-command/012.yaml +10 -0
- pyskillet-0.0.1/evals/add-command/013.yaml +10 -0
- pyskillet-0.0.1/justfile +91 -0
- pyskillet-0.0.1/pyproject.toml +83 -0
- pyskillet-0.0.1/scripts/build_claude_config.py +89 -0
- pyskillet-0.0.1/skillet/__init__.py +23 -0
- pyskillet-0.0.1/skillet/_internal/__init__.py +1 -0
- pyskillet-0.0.1/skillet/_internal/cache.py +112 -0
- pyskillet-0.0.1/skillet/_internal/cache_test.py +66 -0
- pyskillet-0.0.1/skillet/_internal/sdk.py +75 -0
- pyskillet-0.0.1/skillet/_internal/text.py +55 -0
- pyskillet-0.0.1/skillet/_internal/types.py +12 -0
- pyskillet-0.0.1/skillet/cli/__init__.py +9 -0
- pyskillet-0.0.1/skillet/cli/cli_test.py +36 -0
- pyskillet-0.0.1/skillet/cli/commands/__init__.py +1 -0
- pyskillet-0.0.1/skillet/cli/commands/compare.py +69 -0
- pyskillet-0.0.1/skillet/cli/commands/eval.py +135 -0
- pyskillet-0.0.1/skillet/cli/commands/new.py +61 -0
- pyskillet-0.0.1/skillet/cli/commands/tune.py +114 -0
- pyskillet-0.0.1/skillet/cli/display/__init__.py +5 -0
- pyskillet-0.0.1/skillet/cli/display/live.py +125 -0
- pyskillet-0.0.1/skillet/cli/main.py +136 -0
- pyskillet-0.0.1/skillet/compare/__init__.py +5 -0
- pyskillet-0.0.1/skillet/compare/run.py +100 -0
- pyskillet-0.0.1/skillet/config.py +10 -0
- pyskillet-0.0.1/skillet/errors.py +17 -0
- pyskillet-0.0.1/skillet/eval/__init__.py +6 -0
- pyskillet-0.0.1/skillet/eval/judge.py +64 -0
- pyskillet-0.0.1/skillet/eval/run.py +222 -0
- pyskillet-0.0.1/skillet/gaps/__init__.py +5 -0
- pyskillet-0.0.1/skillet/gaps/load.py +59 -0
- pyskillet-0.0.1/skillet/py.typed +0 -0
- pyskillet-0.0.1/skillet/skill/__init__.py +5 -0
- pyskillet-0.0.1/skillet/skill/create.py +57 -0
- pyskillet-0.0.1/skillet/skill/draft.py +49 -0
- pyskillet-0.0.1/skillet/tune/__init__.py +6 -0
- pyskillet-0.0.1/skillet/tune/improve.py +81 -0
- pyskillet-0.0.1/skillet/tune/run.py +162 -0
- pyskillet-0.0.1/tests/e2e/__init__.py +1 -0
- pyskillet-0.0.1/tests/e2e/cli_test.py +12 -0
- pyskillet-0.0.1/tests/e2e/conftest.py +84 -0
- pyskillet-0.0.1/tests/e2e/helpers.py +344 -0
- pyskillet-0.0.1/tests/integration/__init__.py +1 -0
- pyskillet-0.0.1/tests/integration/conftest.py +1 -0
- pyskillet-0.0.1/tests/integration/eval_test.py +12 -0
- pyskillet-0.0.1/uv.lock +1165 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Skillet Development
|
|
2
|
+
|
|
3
|
+
## Workflow
|
|
4
|
+
- Work in git worktrees, tie PRs to GitHub issues
|
|
5
|
+
- Before pushing: `just lint && just test-unit`
|
|
6
|
+
- After pushing: monitor CI checks
|
|
7
|
+
|
|
8
|
+
## Project Structure
|
|
9
|
+
- `.claude-template/` - Source templates with `{{SKILLET_DIR}}` placeholders
|
|
10
|
+
- `.claude/commands/` - Generated (gitignored), built from templates
|
|
11
|
+
- `scripts/build_claude_config.py` - Template builder
|
|
12
|
+
- `tests/e2e/` - End-to-end tests using Claude Agent SDK
|
|
13
|
+
|
|
14
|
+
## Testing
|
|
15
|
+
- E2E tests auto-build `.claude/commands/` via conftest.py
|
|
16
|
+
- `Conversation` helper for multi-turn test flows
|
|
17
|
+
- `setting_sources=["project"]` loads slash commands from `.claude/commands/`
|
|
18
|
+
- Commands in subdirs get namespaced: `skillet/add.md` -> `/skillet:add`
|
|
19
|
+
|
|
20
|
+
## Key Commands
|
|
21
|
+
```bash
|
|
22
|
+
just build-claude # Build .claude/commands/ from templates
|
|
23
|
+
just test-e2e # Run e2e tests
|
|
24
|
+
just test-unit # Run unit tests
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Commit Convention
|
|
28
|
+
|
|
29
|
+
Commits must follow [Conventional Commits](https://www.conventionalcommits.org/) format for automatic version bumping:
|
|
30
|
+
|
|
31
|
+
- `fix: ...` → patch release (0.1.0 → 0.1.1)
|
|
32
|
+
- `feat: ...` → minor release (0.1.0 → 0.2.0)
|
|
33
|
+
- `feat!: ...` or `BREAKING CHANGE:` in body → major release (0.1.0 → 1.0.0)
|
|
34
|
+
- `chore:`, `docs:`, `refactor:`, `test:`, etc. → patch release
|
|
35
|
+
|
|
36
|
+
Releases run nightly at 2am UTC. All commits since the last release are batched together, and the highest-priority bump type wins (breaking > feat > fix).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Add an Eval
|
|
2
|
+
|
|
3
|
+
The user has just noticed that your previous response wasn't what they wanted. Help them add this as an eval for skill development.
|
|
4
|
+
|
|
5
|
+
## Your Task
|
|
6
|
+
|
|
7
|
+
1. **Ask what they expected** — Ask the user what behavior or format they expected instead of what you produced.
|
|
8
|
+
|
|
9
|
+
2. **Check existing evals** — List directories in `{{SKILLET_DIR}}/evals/` to see what eval categories already exist.
|
|
10
|
+
|
|
11
|
+
3. **Suggest eval name options** — Use `AskUserQuestion` to present exactly 3 options:
|
|
12
|
+
- If an existing eval seems related to this issue, suggest it first with "(existing, N evals)"
|
|
13
|
+
- Include 1-2 new name suggestions based on the user's description
|
|
14
|
+
- The user can always type a custom name via "Other"
|
|
15
|
+
|
|
16
|
+
4. **Save the eval** — Write a YAML file to `{{SKILLET_DIR}}/evals/<name>/<number>.yaml` containing:
|
|
17
|
+
- `timestamp`: Current ISO timestamp
|
|
18
|
+
- `prompt`: The user's original prompt (from conversation context)
|
|
19
|
+
- `actual`: Your response (summarized if long)
|
|
20
|
+
- `expected`: What the user said they wanted
|
|
21
|
+
- `name`: The eval name
|
|
22
|
+
|
|
23
|
+
5. **Confirm** — Tell the user the eval was saved and how many evals exist for this name.
|
|
24
|
+
|
|
25
|
+
## Example Interaction
|
|
26
|
+
|
|
27
|
+
User runs `/add`
|
|
28
|
+
|
|
29
|
+
You: "What behavior or format did you expect?"
|
|
30
|
+
|
|
31
|
+
User: "Should have automatically used Playwright when WebFetch failed"
|
|
32
|
+
|
|
33
|
+
You: *checks {{SKILLET_DIR}}/evals/ and finds browser-fallback/ with 2 evals*
|
|
34
|
+
*uses AskUserQuestion with options:*
|
|
35
|
+
- "browser-fallback (existing, 2 evals)" — Add to existing eval category
|
|
36
|
+
- "webfetch-retry" — New category for fetch retry behavior
|
|
37
|
+
- "auto-playwright" — New category for automatic Playwright usage
|
|
38
|
+
|
|
39
|
+
User selects: "browser-fallback (existing, 2 evals)"
|
|
40
|
+
|
|
41
|
+
You: *saves to {{SKILLET_DIR}}/evals/browser-fallback/003.yaml*
|
|
42
|
+
"Eval saved to {{SKILLET_DIR}}/evals/browser-fallback/003.yaml
|
|
43
|
+
|
|
44
|
+
├─ Prompt: "Read https://reddit.com/..."
|
|
45
|
+
├─ Actual: Asked user what to do
|
|
46
|
+
├─ Expected: Automatically use Playwright
|
|
47
|
+
|
|
48
|
+
You now have 3 evals for this skill."
|
|
49
|
+
|
|
50
|
+
## Important
|
|
51
|
+
|
|
52
|
+
- Look at the conversation history to find the prompt and your response
|
|
53
|
+
- Always check existing evals first — grouping related evals is valuable
|
|
54
|
+
- Keep the YAML simple and human-readable
|
|
55
|
+
- Create the {{SKILLET_DIR}}/evals directory if it doesn't exist
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
commit-message:
|
|
8
|
+
prefix: "deps"
|
|
9
|
+
|
|
10
|
+
- package-ecosystem: "github-actions"
|
|
11
|
+
directory: "/"
|
|
12
|
+
schedule:
|
|
13
|
+
interval: "weekly"
|
|
14
|
+
commit-message:
|
|
15
|
+
prefix: "ci"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- '**.py'
|
|
8
|
+
- 'pyproject.toml'
|
|
9
|
+
- 'uv.lock'
|
|
10
|
+
- '.github/workflows/build.yml'
|
|
11
|
+
pull_request:
|
|
12
|
+
paths:
|
|
13
|
+
- '**.py'
|
|
14
|
+
- 'pyproject.toml'
|
|
15
|
+
- 'uv.lock'
|
|
16
|
+
- '.github/workflows/build.yml'
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync --extra dev
|
|
29
|
+
|
|
30
|
+
- name: Build package
|
|
31
|
+
run: uv run just build
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Changelog
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, labeled, unlabeled]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
check:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
# Skip for dependabot PRs and PRs with skip-changelog label
|
|
11
|
+
if: github.actor != 'dependabot[bot]'
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- name: Skip if labeled
|
|
18
|
+
if: contains(github.event.pull_request.labels.*.name, 'skip-changelog')
|
|
19
|
+
run: echo "Skipping changelog check (skip-changelog label present)"
|
|
20
|
+
|
|
21
|
+
- name: Install uv
|
|
22
|
+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-changelog') }}
|
|
23
|
+
uses: astral-sh/setup-uv@v7
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-changelog') }}
|
|
27
|
+
run: uv sync --extra dev
|
|
28
|
+
|
|
29
|
+
- name: Check changelog
|
|
30
|
+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-changelog') }}
|
|
31
|
+
run: uv run just check-changelog origin/${{ github.base_ref }}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'docs/**'
|
|
8
|
+
pull_request:
|
|
9
|
+
paths:
|
|
10
|
+
- 'docs/**'
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
defaults:
|
|
16
|
+
run:
|
|
17
|
+
working-directory: docs
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: pnpm/action-setup@v4
|
|
22
|
+
with:
|
|
23
|
+
version: 10
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: 20
|
|
28
|
+
cache: 'pnpm'
|
|
29
|
+
cache-dependency-path: docs/pnpm-lock.yaml
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: pnpm install
|
|
33
|
+
|
|
34
|
+
- name: Build docs
|
|
35
|
+
run: pnpm build
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- '**.py'
|
|
8
|
+
- 'pyproject.toml'
|
|
9
|
+
- 'uv.lock'
|
|
10
|
+
- 'tests/integration/**'
|
|
11
|
+
- '.github/workflows/integration.yml'
|
|
12
|
+
pull_request:
|
|
13
|
+
paths:
|
|
14
|
+
- '**.py'
|
|
15
|
+
- 'pyproject.toml'
|
|
16
|
+
- 'uv.lock'
|
|
17
|
+
- 'tests/integration/**'
|
|
18
|
+
- '.github/workflows/integration.yml'
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
integration:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v6
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v7
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: uv sync --extra dev
|
|
31
|
+
|
|
32
|
+
- name: Run integration tests
|
|
33
|
+
run: uv run just test-integration
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- '**.py'
|
|
8
|
+
- 'pyproject.toml'
|
|
9
|
+
- 'uv.lock'
|
|
10
|
+
- '.github/workflows/lint.yml'
|
|
11
|
+
pull_request:
|
|
12
|
+
paths:
|
|
13
|
+
- '**.py'
|
|
14
|
+
- 'pyproject.toml'
|
|
15
|
+
- 'uv.lock'
|
|
16
|
+
- '.github/workflows/lint.yml'
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
lint:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync --extra dev
|
|
29
|
+
|
|
30
|
+
- name: Lint
|
|
31
|
+
run: uv run just lint
|
|
32
|
+
|
|
33
|
+
- name: Format check
|
|
34
|
+
run: uv run just format-check
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: PR Monitor
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
checks: read
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
monitor:
|
|
11
|
+
name: 'CI Gate'
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: clankerbot/pr-monitor@v1
|
|
15
|
+
with:
|
|
16
|
+
job-name: 'CI Gate'
|
|
17
|
+
excluded-jobs: 'deploy/netlify, Header rules, Pages changed, Redirect rules'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
# Detect what files changed between this tag and the previous one
|
|
10
|
+
changes:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
outputs:
|
|
13
|
+
package: ${{ steps.filter.outputs.package }}
|
|
14
|
+
docs: ${{ steps.filter.outputs.docs }}
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- name: Get previous tag
|
|
21
|
+
id: prev_tag
|
|
22
|
+
run: |
|
|
23
|
+
# Get all tags sorted by version, find the one before current
|
|
24
|
+
prev_tag=$(git tag --sort=-v:refname | grep -E '^v[0-9]' | sed -n '2p')
|
|
25
|
+
if [ -z "$prev_tag" ]; then
|
|
26
|
+
# If no previous tag, compare against initial commit
|
|
27
|
+
prev_tag=$(git rev-list --max-parents=0 HEAD)
|
|
28
|
+
fi
|
|
29
|
+
echo "prev_tag=$prev_tag" >> $GITHUB_OUTPUT
|
|
30
|
+
|
|
31
|
+
- name: Check changed files
|
|
32
|
+
id: filter
|
|
33
|
+
run: |
|
|
34
|
+
# Get list of changed files between previous tag and current
|
|
35
|
+
changed_files=$(git diff --name-only ${{ steps.prev_tag.outputs.prev_tag }}..HEAD)
|
|
36
|
+
|
|
37
|
+
# Check for package-related changes
|
|
38
|
+
if echo "$changed_files" | grep -qE '^(\.claude/|skillet/|pyproject\.toml|uv\.lock|\.python-version|LICENSE|README\.md)'; then
|
|
39
|
+
echo "package=true" >> $GITHUB_OUTPUT
|
|
40
|
+
else
|
|
41
|
+
echo "package=false" >> $GITHUB_OUTPUT
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Check for docs changes
|
|
45
|
+
if echo "$changed_files" | grep -qE '^docs/'; then
|
|
46
|
+
echo "docs=true" >> $GITHUB_OUTPUT
|
|
47
|
+
else
|
|
48
|
+
echo "docs=false" >> $GITHUB_OUTPUT
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Publish to PyPI if package files changed
|
|
52
|
+
pypi:
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
needs: changes
|
|
55
|
+
if: needs.changes.outputs.package == 'true'
|
|
56
|
+
permissions:
|
|
57
|
+
id-token: write # Required for trusted publishing
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v6
|
|
60
|
+
|
|
61
|
+
- name: Install uv
|
|
62
|
+
uses: astral-sh/setup-uv@v7
|
|
63
|
+
|
|
64
|
+
- name: Build package
|
|
65
|
+
run: uv build
|
|
66
|
+
|
|
67
|
+
- name: Publish to PyPI
|
|
68
|
+
run: uv publish --trusted-publishing always
|
|
69
|
+
|
|
70
|
+
# Deploy docs to GitHub Pages if docs files changed
|
|
71
|
+
docs:
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
needs: changes
|
|
74
|
+
if: needs.changes.outputs.docs == 'true'
|
|
75
|
+
permissions:
|
|
76
|
+
pages: write
|
|
77
|
+
id-token: write
|
|
78
|
+
environment:
|
|
79
|
+
name: github-pages
|
|
80
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/checkout@v6
|
|
83
|
+
|
|
84
|
+
- name: Setup Pages
|
|
85
|
+
uses: actions/configure-pages@v5
|
|
86
|
+
|
|
87
|
+
- name: Upload artifact
|
|
88
|
+
uses: actions/upload-pages-artifact@v3
|
|
89
|
+
with:
|
|
90
|
+
path: 'docs/'
|
|
91
|
+
|
|
92
|
+
- name: Deploy to GitHub Pages
|
|
93
|
+
id: deployment
|
|
94
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Security
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- '**.py'
|
|
8
|
+
- 'pyproject.toml'
|
|
9
|
+
- '.github/workflows/security.yml'
|
|
10
|
+
pull_request:
|
|
11
|
+
paths:
|
|
12
|
+
- '**.py'
|
|
13
|
+
- 'pyproject.toml'
|
|
14
|
+
- '.github/workflows/security.yml'
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
bandit:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v7
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: uv sync --extra dev
|
|
27
|
+
|
|
28
|
+
- name: Run security scan
|
|
29
|
+
run: uv run just security
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- '**.py'
|
|
8
|
+
- 'pyproject.toml'
|
|
9
|
+
- 'uv.lock'
|
|
10
|
+
- 'tests/**'
|
|
11
|
+
- '.github/workflows/test.yml'
|
|
12
|
+
pull_request:
|
|
13
|
+
paths:
|
|
14
|
+
- '**.py'
|
|
15
|
+
- 'pyproject.toml'
|
|
16
|
+
- 'uv.lock'
|
|
17
|
+
- 'tests/**'
|
|
18
|
+
- '.github/workflows/test.yml'
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
test:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
matrix:
|
|
25
|
+
python-version: ["3.12", "3.13"]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@v7
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --extra dev
|
|
36
|
+
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: uv run just test-ci
|
|
39
|
+
|
|
40
|
+
- name: Upload coverage
|
|
41
|
+
uses: codecov/codecov-action@v5
|
|
42
|
+
with:
|
|
43
|
+
files: coverage.xml
|
|
44
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Type Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- '**.py'
|
|
8
|
+
- 'pyproject.toml'
|
|
9
|
+
- '.github/workflows/typecheck.yml'
|
|
10
|
+
pull_request:
|
|
11
|
+
paths:
|
|
12
|
+
- '**.py'
|
|
13
|
+
- 'pyproject.toml'
|
|
14
|
+
- '.github/workflows/typecheck.yml'
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
typecheck:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v7
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: uv sync --extra dev
|
|
27
|
+
|
|
28
|
+
- name: Type check
|
|
29
|
+
run: uv run just typecheck
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
name: Nightly Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Run at 2:00 AM UTC every day
|
|
6
|
+
- cron: '0 2 * * *'
|
|
7
|
+
workflow_dispatch: # Allow manual trigger
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
release:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
19
|
+
|
|
20
|
+
- name: Check for new commits since last tag
|
|
21
|
+
id: check
|
|
22
|
+
run: |
|
|
23
|
+
# Get the latest tag
|
|
24
|
+
latest_tag=$(git tag --sort=-v:refname | grep -E '^v[0-9]' | head -n1)
|
|
25
|
+
|
|
26
|
+
if [ -z "$latest_tag" ]; then
|
|
27
|
+
echo "No tags found, will create initial release"
|
|
28
|
+
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
29
|
+
echo "compare_base=$(git rev-list --max-parents=0 HEAD)" >> $GITHUB_OUTPUT
|
|
30
|
+
else
|
|
31
|
+
# Check if there are commits since the last tag
|
|
32
|
+
commits_since_tag=$(git rev-list ${latest_tag}..HEAD --count)
|
|
33
|
+
if [ "$commits_since_tag" -gt 0 ]; then
|
|
34
|
+
echo "Found $commits_since_tag commits since $latest_tag"
|
|
35
|
+
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
36
|
+
echo "compare_base=$latest_tag" >> $GITHUB_OUTPUT
|
|
37
|
+
else
|
|
38
|
+
echo "No new commits since $latest_tag"
|
|
39
|
+
echo "has_changes=false" >> $GITHUB_OUTPUT
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
- name: Configure git
|
|
44
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
45
|
+
run: |
|
|
46
|
+
git config user.name "github-actions[bot]"
|
|
47
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
48
|
+
|
|
49
|
+
- name: Install uv
|
|
50
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
51
|
+
uses: astral-sh/setup-uv@v7
|
|
52
|
+
|
|
53
|
+
- name: Install python-semantic-release
|
|
54
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
55
|
+
run: uv tool install python-semantic-release
|
|
56
|
+
|
|
57
|
+
- name: Determine version bump
|
|
58
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
59
|
+
id: version
|
|
60
|
+
run: |
|
|
61
|
+
compare_base="${{ steps.check.outputs.compare_base }}"
|
|
62
|
+
|
|
63
|
+
# Analyze all commits since last tag to determine bump type
|
|
64
|
+
# Check for breaking changes (highest priority)
|
|
65
|
+
if git log --format=%B ${compare_base}..HEAD | grep -qiE '(BREAKING CHANGE|^[a-z]+!:)'; then
|
|
66
|
+
echo "bump=major" >> $GITHUB_OUTPUT
|
|
67
|
+
echo "Detected: BREAKING CHANGE -> major bump"
|
|
68
|
+
# Check for features
|
|
69
|
+
elif git log --format=%B ${compare_base}..HEAD | grep -qE '^feat(\(.+\))?:'; then
|
|
70
|
+
echo "bump=minor" >> $GITHUB_OUTPUT
|
|
71
|
+
echo "Detected: feat commit -> minor bump"
|
|
72
|
+
# Default to patch
|
|
73
|
+
else
|
|
74
|
+
echo "bump=patch" >> $GITHUB_OUTPUT
|
|
75
|
+
echo "Detected: fixes/chores only -> patch bump"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
- name: Bump version
|
|
79
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
80
|
+
id: bump
|
|
81
|
+
run: |
|
|
82
|
+
semantic-release version --${{ steps.version.outputs.bump }} --no-changelog --no-push --no-vcs-release
|
|
83
|
+
new_version=$(grep -Po '(?<=^version = ")[^"]+' pyproject.toml)
|
|
84
|
+
echo "new_version=$new_version" >> $GITHUB_OUTPUT
|
|
85
|
+
|
|
86
|
+
- name: Commit and tag
|
|
87
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
88
|
+
run: |
|
|
89
|
+
git add pyproject.toml
|
|
90
|
+
git commit -m "chore: release v${{ steps.bump.outputs.new_version }}" || echo "No changes to commit"
|
|
91
|
+
git tag "v${{ steps.bump.outputs.new_version }}"
|
|
92
|
+
|
|
93
|
+
- name: Push changes and tag
|
|
94
|
+
if: steps.check.outputs.has_changes == 'true'
|
|
95
|
+
run: |
|
|
96
|
+
git push origin main
|
|
97
|
+
git push origin "v${{ steps.bump.outputs.new_version }}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Local/dev files
|
|
13
|
+
scribbles
|
|
14
|
+
tmp
|
|
15
|
+
deprecated
|
|
16
|
+
.claude/settings.local.json
|
|
17
|
+
.coverage
|
|
18
|
+
.pnpm-store
|
|
19
|
+
.worktrees
|
|
20
|
+
|
|
21
|
+
# Generated from .claude-template/
|
|
22
|
+
.claude/commands/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Template-based command system for `{{SKILLET_DIR}}` substitution
|
|
12
|
+
- `scripts/build_claude_config.py` for building `.claude/commands/` from templates
|
|
13
|
+
- `just build-claude` command for template building
|
|
14
|
+
- E2E test helpers with `Conversation` class for multi-turn testing
|
|
15
|
+
- Auto-build of commands in e2e test conftest
|
|
16
|
+
- 13 eval files for testing `/skillet:add` command behavior
|
|
17
|
+
- Multi-turn conversation support in eval system
|
|
18
|
+
- Session resumption for sequential prompts in evals
|
|
19
|
+
- Automated nightly release workflow (2am UTC) triggered by git tags
|
|
20
|
+
- Version bump automation using conventional commits
|
|
21
|
+
- Conditional docs deployment to GitHub Pages
|
|
22
|
+
- Commit convention documentation in `CLAUDE.md`
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Renamed PyPI package from `skillet` to `pyskillet` (name was taken)
|
|
26
|
+
- Renamed `/skillet:gap` command to `/skillet:add`
|
|
27
|
+
- Increased `max_turns` from 3 to 10 for complex command workflows
|
|
28
|
+
- Reorganized codebase into domain modules (eval/, compare/, tune/, skill/, gaps/)
|
|
29
|
+
- Separated CLI layer from core API logic
|
|
30
|
+
- Renamed public API functions: `run_eval` -> `evaluate`, `run_compare` -> `compare`, `run_tune` -> `tune`
|
|
31
|
+
- Moved internal utilities to `_internal/` module
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- Initial CLI with `eval`, `new`, `tune`, and `compare` commands
|
|
35
|
+
- Gap capture via `/skillet:gap` Claude Code command
|
|
36
|
+
- Evaluation caching system
|
|
37
|
+
- LLM-as-judge for response validation
|
|
38
|
+
- Live display with spinner animation for parallel evals
|
|
39
|
+
- Python linting with Ruff
|
|
40
|
+
- pytest testing infrastructure with pytest-describe
|
|
41
|
+
- Pre-commit hooks for linting and tests
|
|
42
|
+
- CI workflows for lint, test, and build
|
|
43
|
+
- PR monitor for CI gating
|
|
44
|
+
- PEP 561 py.typed marker for type checking support
|