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.
Files changed (87) hide show
  1. pyskillet-0.0.1/.claude/.gitignore +2 -0
  2. pyskillet-0.0.1/.claude/CLAUDE.md +36 -0
  3. pyskillet-0.0.1/.claude-template/commands/skillet/add.md +55 -0
  4. pyskillet-0.0.1/.github/dependabot.yml +15 -0
  5. pyskillet-0.0.1/.github/workflows/build.yml +31 -0
  6. pyskillet-0.0.1/.github/workflows/changelog.yml +31 -0
  7. pyskillet-0.0.1/.github/workflows/docs.yml +35 -0
  8. pyskillet-0.0.1/.github/workflows/integration.yml +33 -0
  9. pyskillet-0.0.1/.github/workflows/lint.yml +34 -0
  10. pyskillet-0.0.1/.github/workflows/pr-monitor.yml +17 -0
  11. pyskillet-0.0.1/.github/workflows/release.yml +94 -0
  12. pyskillet-0.0.1/.github/workflows/security.yml +29 -0
  13. pyskillet-0.0.1/.github/workflows/test.yml +44 -0
  14. pyskillet-0.0.1/.github/workflows/typecheck.yml +29 -0
  15. pyskillet-0.0.1/.github/workflows/version-bump.yml +97 -0
  16. pyskillet-0.0.1/.gitignore +22 -0
  17. pyskillet-0.0.1/.pre-commit-config.yaml +9 -0
  18. pyskillet-0.0.1/.python-version +1 -0
  19. pyskillet-0.0.1/CHANGELOG.md +44 -0
  20. pyskillet-0.0.1/LICENSE +21 -0
  21. pyskillet-0.0.1/PKG-INFO +149 -0
  22. pyskillet-0.0.1/README.md +126 -0
  23. pyskillet-0.0.1/ROADMAP.md +61 -0
  24. pyskillet-0.0.1/docs/.gitignore +3 -0
  25. pyskillet-0.0.1/docs/.vitepress/config.ts +26 -0
  26. pyskillet-0.0.1/docs/getting-started.md +11 -0
  27. pyskillet-0.0.1/docs/index.md +23 -0
  28. pyskillet-0.0.1/docs/netlify.toml +11 -0
  29. pyskillet-0.0.1/docs/package.json +13 -0
  30. pyskillet-0.0.1/docs/pnpm-lock.yaml +1448 -0
  31. pyskillet-0.0.1/evals/add-command/001.yaml +4 -0
  32. pyskillet-0.0.1/evals/add-command/002.yaml +4 -0
  33. pyskillet-0.0.1/evals/add-command/003.yaml +4 -0
  34. pyskillet-0.0.1/evals/add-command/004.yaml +7 -0
  35. pyskillet-0.0.1/evals/add-command/005.yaml +6 -0
  36. pyskillet-0.0.1/evals/add-command/006.yaml +9 -0
  37. pyskillet-0.0.1/evals/add-command/007.yaml +8 -0
  38. pyskillet-0.0.1/evals/add-command/008.yaml +8 -0
  39. pyskillet-0.0.1/evals/add-command/009.yaml +10 -0
  40. pyskillet-0.0.1/evals/add-command/010.yaml +10 -0
  41. pyskillet-0.0.1/evals/add-command/011.yaml +10 -0
  42. pyskillet-0.0.1/evals/add-command/012.yaml +10 -0
  43. pyskillet-0.0.1/evals/add-command/013.yaml +10 -0
  44. pyskillet-0.0.1/justfile +91 -0
  45. pyskillet-0.0.1/pyproject.toml +83 -0
  46. pyskillet-0.0.1/scripts/build_claude_config.py +89 -0
  47. pyskillet-0.0.1/skillet/__init__.py +23 -0
  48. pyskillet-0.0.1/skillet/_internal/__init__.py +1 -0
  49. pyskillet-0.0.1/skillet/_internal/cache.py +112 -0
  50. pyskillet-0.0.1/skillet/_internal/cache_test.py +66 -0
  51. pyskillet-0.0.1/skillet/_internal/sdk.py +75 -0
  52. pyskillet-0.0.1/skillet/_internal/text.py +55 -0
  53. pyskillet-0.0.1/skillet/_internal/types.py +12 -0
  54. pyskillet-0.0.1/skillet/cli/__init__.py +9 -0
  55. pyskillet-0.0.1/skillet/cli/cli_test.py +36 -0
  56. pyskillet-0.0.1/skillet/cli/commands/__init__.py +1 -0
  57. pyskillet-0.0.1/skillet/cli/commands/compare.py +69 -0
  58. pyskillet-0.0.1/skillet/cli/commands/eval.py +135 -0
  59. pyskillet-0.0.1/skillet/cli/commands/new.py +61 -0
  60. pyskillet-0.0.1/skillet/cli/commands/tune.py +114 -0
  61. pyskillet-0.0.1/skillet/cli/display/__init__.py +5 -0
  62. pyskillet-0.0.1/skillet/cli/display/live.py +125 -0
  63. pyskillet-0.0.1/skillet/cli/main.py +136 -0
  64. pyskillet-0.0.1/skillet/compare/__init__.py +5 -0
  65. pyskillet-0.0.1/skillet/compare/run.py +100 -0
  66. pyskillet-0.0.1/skillet/config.py +10 -0
  67. pyskillet-0.0.1/skillet/errors.py +17 -0
  68. pyskillet-0.0.1/skillet/eval/__init__.py +6 -0
  69. pyskillet-0.0.1/skillet/eval/judge.py +64 -0
  70. pyskillet-0.0.1/skillet/eval/run.py +222 -0
  71. pyskillet-0.0.1/skillet/gaps/__init__.py +5 -0
  72. pyskillet-0.0.1/skillet/gaps/load.py +59 -0
  73. pyskillet-0.0.1/skillet/py.typed +0 -0
  74. pyskillet-0.0.1/skillet/skill/__init__.py +5 -0
  75. pyskillet-0.0.1/skillet/skill/create.py +57 -0
  76. pyskillet-0.0.1/skillet/skill/draft.py +49 -0
  77. pyskillet-0.0.1/skillet/tune/__init__.py +6 -0
  78. pyskillet-0.0.1/skillet/tune/improve.py +81 -0
  79. pyskillet-0.0.1/skillet/tune/run.py +162 -0
  80. pyskillet-0.0.1/tests/e2e/__init__.py +1 -0
  81. pyskillet-0.0.1/tests/e2e/cli_test.py +12 -0
  82. pyskillet-0.0.1/tests/e2e/conftest.py +84 -0
  83. pyskillet-0.0.1/tests/e2e/helpers.py +344 -0
  84. pyskillet-0.0.1/tests/integration/__init__.py +1 -0
  85. pyskillet-0.0.1/tests/integration/conftest.py +1 -0
  86. pyskillet-0.0.1/tests/integration/eval_test.py +12 -0
  87. pyskillet-0.0.1/uv.lock +1165 -0
@@ -0,0 +1,2 @@
1
+ # Generated from .claude-template/
2
+ commands/
@@ -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,9 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: pytest
5
+ name: pytest
6
+ entry: uv run pytest
7
+ language: system
8
+ types: [python]
9
+ pass_filenames: false
@@ -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