skillstate-kit 0.1.1__tar.gz → 0.1.2__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 (54) hide show
  1. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/CHANGELOG.md +9 -0
  2. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/CITATION.cff +1 -1
  3. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/PKG-INFO +14 -1
  4. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/README.md +7 -1
  5. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/PYPI_README.md +13 -0
  6. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/README_TR.md +4 -0
  7. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/cli.md +18 -1
  8. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/compatibility.md +13 -0
  9. skillstate_kit-0.1.2/docs/host-acceptance.md +65 -0
  10. skillstate_kit-0.1.2/docs/releases/0.1.1.md +28 -0
  11. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/releasing.md +1 -1
  12. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/validation.md +5 -1
  13. skillstate_kit-0.1.2/examples/desktop_acceptance/README.md +49 -0
  14. skillstate_kit-0.1.2/examples/desktop_acceptance/SKILL.md +16 -0
  15. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/pyproject.toml +1 -1
  16. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/__init__.py +1 -1
  17. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/cli.py +8 -0
  18. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/compiler.py +1 -1
  19. skillstate_kit-0.1.2/src/skillstate/desktop.py +142 -0
  20. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/hosts.py +3 -0
  21. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/test_compiler_hosts.py +8 -0
  22. skillstate_kit-0.1.2/tests/test_desktop.py +120 -0
  23. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/uv.lock +1 -1
  24. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/.gitignore +0 -0
  25. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/CONTRIBUTING.md +0 -0
  26. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/LICENSE +0 -0
  27. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/SECURITY.md +0 -0
  28. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/architecture.md +0 -0
  29. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/research/DESIGN_TR.md +0 -0
  30. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/research/REPO_INCELEME_TR.md +0 -0
  31. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/docs/research/URUN_MIMARI_V2_TR.md +0 -0
  32. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/examples/managed_runtime.py +0 -0
  33. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/examples/qa/SKILL.md +0 -0
  34. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/scripts/check_wheel.py +0 -0
  35. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/scripts/verify_index.py +0 -0
  36. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/__main__.py +0 -0
  37. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/artifacts.py +0 -0
  38. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/demo.py +0 -0
  39. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/errors.py +0 -0
  40. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/jsonio.py +0 -0
  41. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/mcp_server.py +0 -0
  42. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/models.py +0 -0
  43. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/providers.py +0 -0
  44. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/py.typed +0 -0
  45. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/runtime.py +0 -0
  46. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/schema.py +0 -0
  47. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/service.py +0 -0
  48. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/src/skillstate/store.py +0 -0
  49. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/conftest.py +0 -0
  50. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/test_cli_mcp_provider.py +0 -0
  51. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/test_json_schema.py +0 -0
  52. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/test_publish_verification.py +0 -0
  53. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/test_runtime.py +0 -0
  54. {skillstate_kit-0.1.1 → skillstate_kit-0.1.2}/tests/test_store.py +0 -0
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 — desktop connection and host acceptance
4
+
5
+ - Explicit `connect claude-desktop` / `disconnect claude-desktop` commands, with Microsoft Store and standalone Windows detection, macOS defaults and explicit config paths.
6
+ - Preserve unrelated app settings, isolate server names per project, serialize connection writes, refuse user-modified entries, and roll back configuration on receipt write failure.
7
+ - Include desktop connections in `doctor`; retain state when disconnecting.
8
+ - Disambiguate the source resource directory for root-level SKILL.md files.
9
+ - Add a reproducible synthetic invoice acceptance exercise and report actual host successes and blockers separately.
10
+ - Codex completed a real MCP review and handoff. Claude Desktop discovered the server, displayed a tool permission request, then the call timed out without a result. Antigravity desktop reported tools unavailable; IDE login was not configured. These are not three passing end-to-end host tests.
11
+
3
12
  ## 0.1.1 — public distribution
4
13
 
5
14
  - Self-contained PyPI package description with installation and SDK examples.
@@ -2,7 +2,7 @@ cff-version: 1.2.0
2
2
  message: "Cite this repository and the SKILL.state paper that inspired its explicit-state execution pattern."
3
3
  title: "skillstate-kit"
4
4
  type: software
5
- version: 0.1.1
5
+ version: 0.1.2
6
6
  license: MIT
7
7
  authors:
8
8
  - name: "Atakan Emre"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skillstate-kit
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Compile existing agent skills into portable, validated execution state.
5
5
  Project-URL: Homepage, https://github.com/Atakan-Emre/skillstate-kit
6
6
  Project-URL: Repository, https://github.com/Atakan-Emre/skillstate-kit
@@ -83,6 +83,19 @@ The preparation response contains source text, its fingerprint and the proposal
83
83
 
84
84
  You can also supply an explicitly configured endpoint with `--base-url` and `--model`. Terminal commands do not borrow your IDE's model credentials.
85
85
 
86
+ ## Claude Desktop Chat
87
+
88
+ Version 0.1.2 adds an explicit local connection, separate from Claude Code:
89
+
90
+ ```console
91
+ skillstate connect claude-desktop
92
+ skillstate doctor --mcp
93
+ ```
94
+
95
+ Fully quit and reopen Claude Desktop, use **Chat**, and approve the tool calls you intend to allow. The installer preserves unrelated settings and uses a separate server name per project. Windows standalone/Microsoft Store and macOS paths are supported; `--config PATH` selects a custom location. If two Windows configs exist, choose explicitly. Disconnect with `skillstate disconnect claude-desktop`; run data remains intact.
96
+
97
+ Live acceptance evidence: Codex used eight real MCP calls to record a synthetic invoice review and hand it to Claude Desktop. Desktop discovered the server and requested tool permission, but the call later timed out without a result; the second review was not completed. An independent MCP transport check subsequently passed. The tested Antigravity desktop session reported MCP tools unavailable, and its separate IDE required login. Generated configuration and transport tests do not establish successful execution in those hosts. No claim of universal desktop compatibility is made.
98
+
86
99
  ## Python integration
87
100
 
88
101
  This complete example uses a scripted model. Replace `model` and `record` with your own model and service functions:
@@ -5,10 +5,13 @@
5
5
  Turn an existing `SKILL.md` into a state-backed skill, use it from Codex, Claude Code or Antigravity, and resume work from a durable checkpoint. Embed the same runtime in Python when you need to control every model input and tool operation.
6
6
 
7
7
  [![CI](https://github.com/Atakan-Emre/skillstate-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/Atakan-Emre/skillstate-kit/actions/workflows/ci.yml)
8
+ [![PyPI](https://img.shields.io/pypi/v/skillstate-kit)](https://pypi.org/project/skillstate-kit/)
8
9
  ![Python](https://img.shields.io/badge/python-3.11%2B-blue)
9
10
  ![License](https://img.shields.io/badge/license-MIT-green)
10
11
 
11
- **Release status:** `0.1.1` is an initial alpha. The development repository is private; public package installation uses PyPI. Tested local adapters are not live certification of every host application.
12
+ **Release status:** `0.1.2` is an alpha. The development repository is private; public package installation uses PyPI. See the actual [host acceptance results](docs/host-acceptance.md) before relying on a specific desktop environment.
13
+
14
+ [Published package](https://pypi.org/project/skillstate-kit/) · [Distribution verification](docs/releases/0.1.1.md)
12
15
 
13
16
  [Türkçe başlangıç](docs/README_TR.md) · [CLI](docs/cli.md) · [Architecture](docs/architecture.md) · [Compatibility](docs/compatibility.md) · [Validation](docs/validation.md)
14
17
 
@@ -19,6 +22,7 @@ Turn an existing `SKILL.md` into a state-backed skill, use it from Codex, Claude
19
22
  - **Durable state.** SQLite transactions, revision checks, ownership handoff and a persistent operation journal.
20
23
  - **Controlled execution.** Validate state and tool arguments, retain observations during retries, and stop ambiguous operations from being replayed automatically.
21
24
  - **Three host adapters.** Project-scoped skills and optional STDIO MCP configuration for Codex, Claude Code and Antigravity.
25
+ - **Claude Desktop Chat connection.** Explicit, reversible app configuration with a separate server per project; normal tool approvals still apply.
22
26
  - **A Python SDK.** Bring your own model and tool functions. The core package requires no API key.
23
27
 
24
28
  ## Quick start
@@ -40,6 +44,8 @@ skillstate doctor --mcp
40
44
 
41
45
  After installing the package, run `init` and `generate` in your target project. `--project PATH` can also be placed **before** a subcommand. Generated MCP configurations use this machine's Python/project paths; keep them local. See [installation and compatibility](docs/compatibility.md).
42
46
 
47
+ For Claude Desktop **Chat**, also run `skillstate connect claude-desktop`, then fully quit and reopen the app. Claude Code, Cowork and Desktop Chat have different integration surfaces. Try the [two-reviewer acceptance exercise](examples/desktop_acceptance/README.md) before using production data.
48
+
43
49
  After the host discovers `generate-skill-state`, ask:
44
50
 
45
51
  > Generate skill state from my existing QA skill and install it in this project.
@@ -44,6 +44,19 @@ The preparation response contains source text, its fingerprint and the proposal
44
44
 
45
45
  You can also supply an explicitly configured endpoint with `--base-url` and `--model`. Terminal commands do not borrow your IDE's model credentials.
46
46
 
47
+ ## Claude Desktop Chat
48
+
49
+ Version 0.1.2 adds an explicit local connection, separate from Claude Code:
50
+
51
+ ```console
52
+ skillstate connect claude-desktop
53
+ skillstate doctor --mcp
54
+ ```
55
+
56
+ Fully quit and reopen Claude Desktop, use **Chat**, and approve the tool calls you intend to allow. The installer preserves unrelated settings and uses a separate server name per project. Windows standalone/Microsoft Store and macOS paths are supported; `--config PATH` selects a custom location. If two Windows configs exist, choose explicitly. Disconnect with `skillstate disconnect claude-desktop`; run data remains intact.
57
+
58
+ Live acceptance evidence: Codex used eight real MCP calls to record a synthetic invoice review and hand it to Claude Desktop. Desktop discovered the server and requested tool permission, but the call later timed out without a result; the second review was not completed. An independent MCP transport check subsequently passed. The tested Antigravity desktop session reported MCP tools unavailable, and its separate IDE required login. Generated configuration and transport tests do not establish successful execution in those hosts. No claim of universal desktop compatibility is made.
59
+
47
60
  ## Python integration
48
61
 
49
62
  This complete example uses a scripted model. Replace `model` and `record` with your own model and service functions:
@@ -24,6 +24,10 @@ skillstate doctor --mcp
24
24
 
25
25
  ## Otomatik üretim
26
26
 
27
+ Claude Desktop'ın **Chat** bölümünü kullanıyorsanız ayrıca `skillstate connect claude-desktop` çalıştırıp uygulamadan tamamen çıkın ve yeniden açın. Bu bağlantı Claude Code kurulumundan ayrıdır. Araç izinlerini uygulama içinde siz verirsiniz. `skillstate disconnect claude-desktop` bağlantıyı kaldırır, görev durumunu korur. Windows Store sürümü de desteklenir; birden fazla ayar dosyası bulunursa `--config DOSYA` ile seçilir.
28
+
29
+ Gerçek uygulama testlerinin sonucu [kabul raporunda](host-acceptance.md), tekrar edilebilir örnek ise [örnek projede](../examples/desktop_acceptance/README.md). Codex'in gerçek MCP devri doğrulandı; diğer uygulamalardaki eksik onay ve bağlantı adımları başarılı sayılmadı.
30
+
27
31
  Kurulumdan sonra agent'a “Generate skill state; bu skill'i durum yapısına dönüştür” diyebilirsiniz. Üretici kaynak envanterini hazırlayıp agent'ın önerdiği şemayı doğrular.
28
32
 
29
33
  Doğrudan `generate`, yönergeleri koruyan sınırlı bir genel ilerleme şeması oluşturur. Alana özel dönüşüm için agent destekli `--prepare`/`--proposal` akışı veya yapılandırılmış `--base-url`/`--model` kullanılır. Terminal, IDE model hesabını otomatik kullanmaz.
@@ -11,7 +11,24 @@ skillstate validate qa-state
11
11
  skillstate doctor --mcp
12
12
  ```
13
13
 
14
- Omit `--mcp` for CLI-only host usage. Omit host flags to install all three adapters. Installation is project-local; global installation and hooks are not included in 0.1.0.
14
+ Omit `--mcp` for CLI-only host usage. Omit host flags to install all three project adapters. `init` remains project-local; no hooks are installed.
15
+
16
+ ### Claude Desktop Chat connection
17
+
18
+ ```text
19
+ skillstate connect claude-desktop
20
+ skillstate doctor --mcp
21
+ skillstate disconnect claude-desktop
22
+ ```
23
+
24
+ `connect` explicitly merges an app-wide MCP entry for this project. It requires
25
+ the `mcp` extra and reports the config path and server name. Fully quit/reopen
26
+ Claude Desktop and use Chat; allow only the tool calls you intend to authorize.
27
+ Pass `--config PATH` when auto-detection is ambiguous or your platform uses a
28
+ custom location. `disconnect` uses the saved receipt and retains all run data.
29
+ It refuses to remove user-modified entries. `uninstall` does not perform this
30
+ separate desktop disconnection. See [compatibility](compatibility.md) for the
31
+ tested platform/surface limitations.
15
32
 
16
33
  `generate` defaults to bounded tracking state while preserving the source instructions. For a Python project, `--profile python-tests` supplies test-oriented tracking instructions. It scans AST without importing project modules. Multiple source SKILL.md files require selecting one; it does not silently combine unrelated skills.
17
34
 
@@ -7,6 +7,7 @@
7
7
  | Codex | `.agents/skills/<name>/SKILL.md` | `.codex/config.toml` | Native CLI skill + STDIO MCP |
8
8
  | Claude Code | `.claude/skills/<name>/SKILL.md` | `.mcp.json` | Native CLI skill + STDIO MCP |
9
9
  | Antigravity | `.agents/skills/<name>/SKILL.md` | `.agents/mcp_config.json` | Native CLI skill + STDIO MCP |
10
+ | Claude Desktop Chat | MCP generation tools | App-wide `claude_desktop_config.json`, one project per entry | Explicit `connect` command; tool approvals required |
10
11
 
11
12
  The shared `.agents/skills` output is installed once for Codex/Antigravity. State is canonical in one project-local database, not copied into each host folder. These adapters target documented local discovery/configuration paths, not cloud or remote sessions.
12
13
 
@@ -22,6 +23,18 @@ If discovery does not refresh, reload/restart the host as its documentation requ
22
23
 
23
24
  ## Verification levels
24
25
 
26
+ ### Claude Desktop Chat (0.1.2)
27
+
28
+ Use `skillstate connect claude-desktop` in the target project, then fully quit/reopen Claude Desktop. The command auto-detects the standalone or Microsoft Store Windows config and the standard macOS path. Use `--config PATH` for other locations or ambiguous installs. `disconnect claude-desktop` removes only the owned, unmodified server entry; it preserves other settings and project state. `uninstall` handles project adapters separately.
29
+
30
+ The connection writes an app-wide config containing an absolute interpreter and project path. A project-local receipt tracks ownership; a neighboring SQLite lock serializes this package's config writers. Atomic replacement handles individual writes; this is not a cross-file crash transaction. Keep the receipt to manage the connection. After moving a project, disconnect from the old location and reconnect from the new one. `doctor` checks the saved connection but cannot approve tools or certify host execution.
31
+
32
+ Use the Chat surface. Cowork and Code in Desktop have different local tool rules; the tested build displayed a reserved-server-name warning for those surfaces. Chat still discovered the server. See [MCP SDK desktop setup](https://py.sdk.modelcontextprotocol.io/get-started/real-host/) and the [actual acceptance report](host-acceptance.md).
33
+
34
+ ### Antigravity product variants
35
+
36
+ The workspace config path is documented for Antigravity IDE/CLI. Antigravity desktop 2.0 also has an Installed MCP Servers settings surface. In the live desktop test, the model did not receive the project MCP tools despite generated files and a populated tool cache; no state was generated. The separate IDE opened to login. Do not interpret these adapters as a passing test for every Antigravity product. [Official MCP configuration](https://antigravity.google/docs/mcp).
37
+
25
38
  1. **Generated:** expected files/configuration exist.
26
39
  2. **Validated:** managed content and configuration match.
27
40
  3. **Transport tested:** actual SDK client/server initialize/list/call succeeds (`doctor --mcp`).
@@ -0,0 +1,65 @@
1
+ # Host acceptance — 2026-09-07
2
+
3
+ This exercise used a new local workspace and a synthetic invoice with line totals
4
+ 10, 20 and 30 EUR. The baseline server was installed from public PyPI 0.1.1 into
5
+ a separate, non-editable environment. New Claude Desktop connection code was
6
+ then exercised from the development checkout. No production data was used.
7
+
8
+ | Host/surface | Observation | Verdict |
9
+ |---|---|---|
10
+ | Installed Codex CLI, actual model | Eight successful MCP calls; invoice total and artifact persisted; owner transferred to claude-desktop | First review and handoff passed |
11
+ | Claude Desktop 1.46388.4.0, Chat | Server discovered; actual model requested `run_context`; app displayed tool permission, then the call timed out without a result | Discovery passed; continuation failed in this attempt |
12
+ | Claude Desktop Cowork/Code | App displayed a reserved internal server name warning for this local entry | Not supported by this tested connection |
13
+ | Antigravity desktop, Gemini 3.8 Flash High | Opened the project; model reported MCP tools unavailable; no skill or run was created | Requested MCP task failed |
14
+ | Separate Antigravity IDE | Login/onboarding screen, including optional migration dialog | No model task executed |
15
+ | Claude Code standalone | Not separately exercised | No live claim |
16
+
17
+ ## Independently checked Codex result
18
+
19
+ - Run: `desktop-acceptance-01`; revision **3**; owner `claude-desktop`.
20
+ - Status: **ready**, no pending operation; deliberately not completed.
21
+ - Invoice `INV-DEMO`; calculated total **60 EUR**.
22
+ - Evidence artifact: `3324d313470e08682bd6dd9aab6ce24cc357ae4bd5de593bdd04005a4147fd60`.
23
+ - Successful calls: `run_open`, `run_context`, `run_update`, `artifact_put`,
24
+ `run_context`, `run_update`, `run_context`, `run_handoff`.
25
+ - A fresh process read the persisted run after the Codex process ended. The
26
+ handoff did not depend on keeping its original conversation alive.
27
+
28
+ The first Codex attempt used a non-interactive policy that could not approve a
29
+ write tool and stopped without opening a run. The successful retry used Codex's
30
+ supported automatic review mode with a workspace-write sandbox. This is a host
31
+ approval requirement, not permission to bypass safeguards.
32
+
33
+ Claude's first tool request was not approved by the test driver. It eventually
34
+ returned a timeout/no-result error after approximately four minutes. The UI
35
+ suggested an unresponsive or crashed server; that explanation was not established.
36
+ An independent `doctor --mcp` check on the same project subsequently passed.
37
+ No second review or completion was recorded. This report does not claim a
38
+ completed Codex-to-Claude workflow. Ordinary user tool approval remains part of
39
+ setup. The native computer-use driver cannot grant security/privacy permissions
40
+ on the user's behalf. Retry from the saved run after resolving host permissions;
41
+ do not recreate or reset the run.
42
+
43
+ Antigravity wrote its own final diagnostic reporting unavailable tools. Its
44
+ local tool cache contained the 12 server schemas, but that did not prove the
45
+ model received callable tools. This distinction matters: generated files,
46
+ discovery caches, actual calls and task completion are separate evidence levels.
47
+
48
+ ## Fixes and reproducibility
49
+
50
+ The exercise exposed missing Claude Desktop setup and an ambiguous `..` in the
51
+ root source directory instruction. Version 0.1.2 adds a reversible desktop
52
+ connection, config ownership/conflict checks, Windows Store path detection,
53
+ doctor checks and an unambiguous source directory. Regression tests cover
54
+ preservation, multiple projects, modified entries, config ambiguity and write
55
+ failure rollback.
56
+
57
+ The portable [sample project](../examples/desktop_acceptance/README.md) documents
58
+ both prompts and independent state/event checks. Host behavior remains subject
59
+ to its installed version, account, model and permissions. These observations do
60
+ not establish paper benchmark reproduction or universal task reliability.
61
+
62
+ Local validation before release included the complete test suite, the 85%
63
+ statement/branch coverage gate, formatting/lint, wheel/sdist metadata validation,
64
+ and a clean wheel installation with an actual 12-tool STDIO MCP handshake.
65
+ The release workflow reruns the full OS/Python matrix before publishing.
@@ -0,0 +1,28 @@
1
+ # 0.1.1 release evidence
2
+
3
+ Published on **2026-09-07 (Europe/Istanbul)** as the first public alpha distribution. The GitHub repository remains private.
4
+
5
+ - [PyPI release](https://pypi.org/project/skillstate-kit/0.1.1/)
6
+ - [Initial publication](https://github.com/Atakan-Emre/skillstate-kit/actions/runs/34062326878), source commit `0d4ae46198dc621cf986967a6a5959942f625d6e`.
7
+ - [Complete publishing and post-publication verification](https://github.com/Atakan-Emre/skillstate-kit/actions/runs/34062474628), workflow commit `7d7b6cd`.
8
+
9
+ The latter run passed six Windows/macOS/Ubuntu and Python 3.11/3.13 jobs, distribution build and clean installation, publication recovery against existing files, and registry download/hash/installation verification. Its artifacts match the initial upload. TestPyPI was intentionally not used; no TestPyPI validation is claimed.
10
+
11
+ ## Local consumer verification
12
+
13
+ A new Windows/Python 3.12 environment installed `skillstate-kit==0.1.1` directly from `https://pypi.org/simple` with cache disabled. The core-only installation completed the scripted demo. Installing the `mcp,http` extras then passed project initialization, source skill generation, bundle validation and a real STDIO MCP handshake with 12 tools.
14
+
15
+ The local test suite passed **104 tests**, with **one skipped** because local Windows symlink privileges were unavailable. Combined package statement/branch coverage was **87.12%**. Five of these tests specifically reject substituted hashes, changed download bytes, yanked files and unexpected registry hosts before package execution.
16
+
17
+ ## Published file integrity
18
+
19
+ Both files were downloaded from the registry and checked against the CI artifacts before the downloaded wheel was installed in another clean environment.
20
+
21
+ ```text
22
+ 244b4e7d392b6f22eb795b3b64ac55b89b82ebf62385704bbabd58172e1c0f6f skillstate_kit-0.1.1-py3-none-any.whl
23
+ 9515e839e72f717f27e0ef6ee7f6d9e476d9e301d77ef77f1cdd7e982c618455 skillstate_kit-0.1.1.tar.gz
24
+ ```
25
+
26
+ Publishing uses the `Atakan-Emre/skillstate-kit` repository, `publish.yml`, the `pypi` GitHub environment and short-lived OIDC credentials. The environment permits only `main`. No permanent PyPI API token was added to the repository.
27
+
28
+ These checks establish the release and tested contracts. They do not establish defect-free operation, automatic native-tool interception, live task compatibility with every IDE version or a reproduction of the paper's benchmarks.
@@ -13,7 +13,7 @@ The repository currently stays private. Build a wheel/sdist after the test and p
13
13
 
14
14
  ## PyPI publication
15
15
 
16
- PyPI publication makes distributions publicly downloadable, even if GitHub remains private. Publication has been requested for this project; the first public candidate is 0.1.1. Registry presence and workflow results, not a prepared document, establish that publication actually happened.
16
+ PyPI publication makes distributions publicly downloadable, even if GitHub remains private. Version 0.1.1 is published; see [release evidence](releases/0.1.1.md). Registry presence and workflow results, not a prepared document, establish that a new publication actually happened.
17
17
 
18
18
  The manually dispatched `.github/workflows/publish.yml` runs the full CI matrix, builds once and verifies a clean wheel installation before uploading to PyPI. It then downloads both published distributions, verifies their SHA-256 hashes against the tested artifacts and exercises the downloaded wheel in a fresh environment. Publishing jobs alone receive `id-token: write`; they do not check out or execute project code. `skip-existing` supports interrupted-run recovery; differing registry hashes fail verification.
19
19
 
@@ -2,13 +2,17 @@
2
2
 
3
3
  Tests validate contracts, not an absence of all possible defects. A successful generation reports structural checks; it does not invent live execution evidence.
4
4
 
5
+ ## Desktop acceptance (2026-09-07)
6
+
7
+ See [host acceptance](host-acceptance.md) for a real Codex MCP review/handoff and the observed Claude Desktop/Antigravity blockers. The original configuration-only checks below are historical and do not supersede that report.
8
+
5
9
  ## Initial release checks (2026-09-06)
6
10
 
7
11
  - Local Windows / Python 3.12.7: **99 passed, 1 skipped**, **87.12%** combined statement/branch coverage. The skipped test requires symlink privileges. CLI Unicode output was also verified through an ASCII-only pipe.
8
12
  - A scripted 100-operation run retained identical model-context byte sizes while its audit grew to 202 events. This checks history isolation, not real-model task quality or token savings.
9
13
  - Fresh wheel installation in a separate environment passed demo, generation, bundle validation and a real 12-tool MCP STDIO handshake (protocol `2025-11-25`). Wheel/sdist passed `twine check`.
10
14
  - Both generated skill files passed Codex's skill-format validator. The installed Codex CLI discovered the generated `skillstate-kit` MCP entry and reported it enabled. This was configuration discovery, not a live model completing the workflow.
11
- - Claude Code and Antigravity applications were not available for live task verification. Their generated configuration and shared state protocol are covered by automated tests.
15
+ - Claude Code and Antigravity were not exercised as live applications in this initial check. This did not establish that the desktop applications were absent from the computer. Their generated configuration and shared state protocol were covered by automated tests.
12
16
 
13
17
  The release's CI link records the exact release commit and cross-platform results; use it when checking a downloaded distribution. These observations do not certify every host version or arbitrary generated domain schema.
14
18
 
@@ -0,0 +1,49 @@
1
+ # Real host acceptance exercise
2
+
3
+ Copy this directory into an empty local workspace. Use synthetic data throughout.
4
+ The two host conversations must share the same workspace, not different worktrees.
5
+
6
+ ```console
7
+ python -m pip install "skillstate-kit[mcp]"
8
+ skillstate init --mcp
9
+ skillstate generate SKILL.md --name invoice-audit --install
10
+ skillstate doctor --mcp
11
+ ```
12
+
13
+ For Claude Desktop **Chat**, additionally run `skillstate connect claude-desktop`
14
+ and fully quit/reopen the app. This is separate from Claude Code and Cowork.
15
+ Normal host tool approvals remain necessary. Do not disable host safeguards.
16
+
17
+ Ask the first host:
18
+
19
+ > Use the skillstate-kit MCP tools to open invoice-audit as owner codex, run ID
20
+ > invoice-test-01. Read context, calculate the invoice total, record the facts and
21
+ > a text evidence artifact, then hand off to owner claude-desktop. Do not complete
22
+ > the run. Report actual tool failures instead of simulating success.
23
+
24
+ Ask Claude Desktop Chat:
25
+
26
+ > Use the local skillstate MCP tools to read invoice-test-01 and its evidence.
27
+ > Independently check the arithmetic, record the second review as owner
28
+ > claude-desktop, then complete the run if all checks pass. Report its final
29
+ > revision, owner and status. Do not reset the run or invent tool results.
30
+
31
+ Verify outside the host conversations:
32
+
33
+ ```console
34
+ skillstate run context invoice-test-01
35
+ skillstate run events invoice-test-01
36
+ ```
37
+
38
+ The total must be 60 EUR, the artifact must contain the arithmetic, the owner
39
+ must be claude-desktop, and the status must be completed. The event stream must
40
+ show the initial review, handoff and second review. A chat answer alone does not
41
+ prove success. If a host stops for approval, status must remain incomplete.
42
+
43
+ To test generation by a host, ask it to generate a separate `invoice-semantic`
44
+ skill from SKILL.md using `generation_prepare` and `generation_apply`, citing
45
+ the returned source hash. Inspect the resulting schema and run it separately.
46
+
47
+ Disconnect the desktop entry with `skillstate disconnect claude-desktop`.
48
+ Run data is retained for inspection. `skillstate uninstall` only removes the
49
+ project host files it owns; it does not disconnect the app-wide desktop entry.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: invoice-audit
3
+ description: Audit a synthetic invoice and pass verified state to another reviewer.
4
+ ---
5
+
6
+ # Invoice audit
7
+
8
+ This fixture contains no personal or production data.
9
+ Invoice INV-DEMO has three line totals: 10, 20 and 30 EUR.
10
+
11
+ 1. Calculate the sum and record the invoice ID, currency and total in state.
12
+ 2. Store a text evidence artifact containing the arithmetic and its result.
13
+ 3. The first reviewer transfers the run to a second reviewer without completing it.
14
+ 4. The second reviewer reads the persistent context and evidence, independently
15
+ checks that the total is 60 EUR, and records a successful review.
16
+ 5. Complete only after the second review. Never invent an executed external tool.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "skillstate-kit"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Compile existing agent skills into portable, validated execution state."
9
9
  readme = "docs/PYPI_README.md"
10
10
  requires-python = ">=3.11"
@@ -15,7 +15,7 @@ from .runtime import SkillRuntime
15
15
  from .schema import apply_patch
16
16
  from .store import SQLiteStore
17
17
 
18
- __version__ = "0.1.1"
18
+ __version__ = "0.1.2"
19
19
  __all__ = [
20
20
  "BudgetExceeded",
21
21
  "ConflictError",
@@ -62,6 +62,10 @@ def parser() -> argparse.ArgumentParser:
62
62
  subs.add_parser("status", help="List local runs")
63
63
  subs.add_parser("demo", help="Run the explicit offline scripted-model example")
64
64
  subs.add_parser("serve", help="Start a project-scoped STDIO MCP server")
65
+ for command in ("connect", "disconnect"):
66
+ desktop = subs.add_parser(command, help=f"{command.title()} this project to Claude Desktop")
67
+ desktop.add_argument("host", choices=("claude-desktop",))
68
+ desktop.add_argument("--config", type=Path, help="Explicit desktop config path")
65
69
  run = subs.add_parser("run", help="Operate a durable run")
66
70
  r = run.add_subparsers(dest="operation", required=True)
67
71
  open_p = r.add_parser("open")
@@ -114,6 +118,10 @@ def dispatch(args) -> dict | list | None:
114
118
 
115
119
  if args.command == "init":
116
120
  return hosts.install(project, args.host, mcp=args.mcp)
121
+ if args.command in ("connect", "disconnect"):
122
+ from .desktop import connection
123
+
124
+ return connection(project, config=args.config, remove=args.command == "disconnect")
117
125
  if args.command == "generate":
118
126
  if args.prepare:
119
127
  return compiler.prepare(project, args.source, args.name)
@@ -216,7 +216,7 @@ def tracking_ir(inventory: dict, name: str | None = None, profile: str = "auto")
216
216
  )
217
217
  instructions = (
218
218
  f"Source procedure: {primary['path']}. Resolve its resource paths relative to "
219
- f"{Path(primary['path']).parent.as_posix()}. Follow the user's current task and authorizations.\n\n"
219
+ f"`{Path(primary['path']).parent.as_posix()}` within the project root. Follow the user's current task and authorizations.\n\n"
220
220
  + body
221
221
  + "\n\nTrack active_step, completed_steps, facts, blockers and artifacts. "
222
222
  "Only mark steps complete after checking their results. Retain facts needed by later steps. "
@@ -0,0 +1,142 @@
1
+ """Explicit, reversible Claude Desktop connections to one local project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+ import os
7
+ import sqlite3
8
+ import sys
9
+ from contextlib import closing
10
+ from pathlib import Path
11
+
12
+ from .errors import ConflictError, ValidationError
13
+ from .hosts import _config_document
14
+ from .jsonio import atomic_write, digest, dumps, read_json, within
15
+
16
+
17
+ def checks(project: Path) -> list[dict]:
18
+ """Inspect a saved connection; never imply that the host loaded it."""
19
+ receipt_path = within(project.resolve(), ".skillstate/local/claude-desktop.json")
20
+ if not receipt_path.exists():
21
+ return []
22
+ try:
23
+ receipt = read_json(receipt_path)
24
+ path = Path(receipt["config"])
25
+ doc = _config_document(path, "json")
26
+ matching = doc.get("mcpServers", {}).get(receipt["server_name"]) == receipt["entry"]
27
+ executable = Path(receipt["entry"]["command"]).is_file()
28
+ except (KeyError, TypeError, AttributeError, ValueError, OSError, ValidationError):
29
+ matching, executable = False, False
30
+ return [
31
+ {"check": "claude-desktop config", "kind": "mcp_configuration", "ok": matching},
32
+ {"check": "claude-desktop interpreter", "kind": "executable", "ok": executable},
33
+ ]
34
+
35
+
36
+ def config_path() -> Path:
37
+ """Resolve standalone and Microsoft Store installs without reading credentials."""
38
+ if sys.platform == "win32":
39
+ local = os.environ.get("LOCALAPPDATA")
40
+ packaged = (
41
+ Path(local)
42
+ / "Packages/Claude_pzs8sxrjxfjjc/LocalCache/Roaming/Claude/claude_desktop_config.json"
43
+ if local
44
+ else None
45
+ )
46
+ roaming = os.environ.get("APPDATA")
47
+ regular = Path(roaming) / "Claude/claude_desktop_config.json" if roaming else None
48
+ existing = [p for p in (regular, packaged) if p is not None and p.is_file()]
49
+ if len(existing) > 1:
50
+ raise ValidationError("Multiple Claude Desktop configs found; select one with --config")
51
+ if existing:
52
+ return existing[0]
53
+ if packaged is not None and packaged.parent.is_dir():
54
+ return packaged
55
+ if regular is not None:
56
+ return regular
57
+ elif sys.platform == "darwin":
58
+ return Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
59
+ raise ValidationError("Specify the Claude Desktop config path with --config on this platform")
60
+
61
+
62
+ def connection(project: Path, *, config: Path | None = None, remove: bool = False) -> dict:
63
+ """Merge only an owned project-specific server; preserve other app settings."""
64
+ project = project.resolve()
65
+ receipt_path = within(project, ".skillstate/local/claude-desktop.json")
66
+ receipt = read_json(receipt_path) if receipt_path.exists() else None
67
+ if remove and receipt is None:
68
+ return {"connected": False, "changed": False, "state_retained": True}
69
+ if receipt is not None and (
70
+ not isinstance(receipt, dict)
71
+ or set(receipt) != {"config", "server_name", "entry"}
72
+ or not isinstance(receipt["config"], str)
73
+ or not isinstance(receipt["entry"], dict)
74
+ ):
75
+ raise ValidationError("Invalid Claude Desktop connection receipt")
76
+ target = config or (Path(receipt["config"]) if receipt else config_path())
77
+ target = within(target.absolute().parent, target.absolute())
78
+ server_name = "skillstate-" + digest(str(project))[:12]
79
+ if receipt and (receipt["config"] != str(target) or receipt["server_name"] != server_name):
80
+ raise ConflictError("Disconnect the existing Claude Desktop connection first")
81
+ if not remove and importlib.util.find_spec("mcp") is None:
82
+ raise ValidationError("Install skillstate-kit[mcp] before connecting Claude Desktop")
83
+ entry = {
84
+ "command": sys.executable,
85
+ "args": ["-m", "skillstate", "--project", str(project), "serve"],
86
+ }
87
+ target.parent.mkdir(parents=True, exist_ok=True)
88
+ # Serialize our writers across projects and processes sharing this app config.
89
+ lock = within(target.parent, target.name + ".skillstate-lock.sqlite3")
90
+ with closing(sqlite3.connect(lock, timeout=10, isolation_level=None)) as db:
91
+ db.execute("BEGIN IMMEDIATE")
92
+ try:
93
+ original = target.read_bytes() if target.exists() else None
94
+ doc = _config_document(target, "json")
95
+ servers = doc.setdefault("mcpServers", {})
96
+ if not isinstance(servers, dict):
97
+ raise ValidationError("MCP config section must be an object")
98
+ current = servers.get(server_name)
99
+ if current is not None and (receipt is None or current != receipt["entry"]):
100
+ raise ConflictError("Refusing to change a user-owned Claude Desktop server entry")
101
+ if remove:
102
+ servers.pop(server_name, None)
103
+ else:
104
+ servers[server_name] = entry
105
+ updated = (dumps(doc) + "\n").encode("utf-8")
106
+ # Also detect non-cooperating editor writes observed since the initial read.
107
+ if (target.read_bytes() if target.exists() else None) != original:
108
+ raise ConflictError("Claude Desktop config changed during connection; retry")
109
+ changed = updated != original
110
+ if changed:
111
+ atomic_write(target, updated)
112
+ try:
113
+ if remove:
114
+ receipt_path.unlink(missing_ok=True)
115
+ else:
116
+ atomic_write(
117
+ receipt_path,
118
+ dumps({"config": str(target), "server_name": server_name, "entry": entry})
119
+ + "\n",
120
+ )
121
+ except BaseException:
122
+ if changed:
123
+ if original is None:
124
+ target.unlink(missing_ok=True)
125
+ else:
126
+ atomic_write(target, original)
127
+ raise
128
+ db.execute("COMMIT")
129
+ finally:
130
+ if db.in_transaction:
131
+ db.execute("ROLLBACK")
132
+ return {
133
+ "connected": not remove,
134
+ "changed": changed,
135
+ "host": "claude-desktop",
136
+ "config": str(target),
137
+ "server_name": server_name,
138
+ "project": str(project),
139
+ "state_retained": True,
140
+ "live_host_verified": False,
141
+ "next": "Fully quit and reopen Claude Desktop. Use Chat for local MCP, not Cowork.",
142
+ }
@@ -268,6 +268,8 @@ def uninstall(project: Path) -> dict:
268
268
 
269
269
 
270
270
  def doctor(project: Path) -> dict:
271
+ from .desktop import checks as desktop_checks
272
+
271
273
  project = project.resolve()
272
274
  manifest = _manifest(project)
273
275
  checks = []
@@ -306,6 +308,7 @@ def doctor(project: Path) -> dict:
306
308
  "ok": importlib.util.find_spec("mcp") is not None,
307
309
  }
308
310
  )
311
+ checks.extend(desktop_checks(project))
309
312
  return {
310
313
  "ok": bool(checks) and all(check["ok"] for check in checks),
311
314
  "checks": checks,
@@ -198,6 +198,14 @@ def test_three_host_sequential_handoff_preserves_state(project):
198
198
  # This verifies our protocol, not live IDE applications.
199
199
 
200
200
 
201
+ def test_root_skill_resource_directory_is_unambiguous(project):
202
+ (project / "SKILL.md").write_text("# Check\n1. Read fixtures/input.json.\n", encoding="utf-8")
203
+ generated = generate(project, "SKILL.md", name="root-check")
204
+ service = ProjectService(project)
205
+ opened = service.open_run(generated["name"], "codex", "root-run", {})
206
+ assert "relative to `.` within the project root." in opened["skill"]["instructions"]
207
+
208
+
201
209
  def test_source_drift_is_reported_and_blocks_handoff(project):
202
210
  generated = generate(project, SOURCE)
203
211
  service = ProjectService(project)
@@ -0,0 +1,120 @@
1
+ import json
2
+ from concurrent.futures import ThreadPoolExecutor
3
+
4
+ import pytest
5
+
6
+ from skillstate import desktop
7
+ from skillstate.cli import main
8
+ from skillstate.errors import ConflictError, ValidationError
9
+ from skillstate.hosts import doctor
10
+
11
+
12
+ def test_desktop_connect_reconnect_disconnect_preserves_settings(project, tmp_path):
13
+ config = tmp_path / "desktop" / "claude_desktop_config.json"
14
+ config.parent.mkdir()
15
+ original = {"preferences": {"theme": "dark"}, "mcpServers": {"other": {"command": "keep"}}}
16
+ config.write_text(json.dumps(original))
17
+ first = desktop.connection(project, config=config)
18
+ assert first["connected"] and first["changed"]
19
+ assert doctor(project)["ok"]
20
+ assert not desktop.connection(project)["changed"]
21
+ value = json.loads(config.read_text())
22
+ entry = value["mcpServers"][first["server_name"]]
23
+ assert entry["args"][-2:] == [str(project.resolve()), "serve"]
24
+ assert value["preferences"] == original["preferences"]
25
+ assert value["mcpServers"]["other"] == original["mcpServers"]["other"]
26
+ assert not desktop.connection(project, remove=True)["connected"]
27
+ assert json.loads(config.read_text()) == original
28
+
29
+
30
+ def test_desktop_refuses_user_modified_entry(project, tmp_path):
31
+ config = tmp_path / "desktop.json"
32
+ result = desktop.connection(project, config=config)
33
+ value = json.loads(config.read_text())
34
+ value["mcpServers"][result["server_name"]]["command"] = "custom"
35
+ config.write_text(json.dumps(value))
36
+ before = config.read_bytes()
37
+ assert not doctor(project)["ok"]
38
+ for remove in (False, True):
39
+ with pytest.raises(ConflictError):
40
+ desktop.connection(project, remove=remove)
41
+ assert config.read_bytes() == before
42
+
43
+
44
+ def test_desktop_multiple_projects_and_config_switch(project, tmp_path):
45
+ config = tmp_path / "desktop.json"
46
+ first = desktop.connection(project, config=config)
47
+ second = desktop.connection(tmp_path / "second", config=config)
48
+ assert first["server_name"] != second["server_name"]
49
+ desktop.connection(project, remove=True)
50
+ assert list(json.loads(config.read_text())["mcpServers"]) == [second["server_name"]]
51
+ with pytest.raises(ConflictError):
52
+ desktop.connection(tmp_path / "second", config=tmp_path / "other.json")
53
+
54
+
55
+ def test_concurrent_desktop_connections_do_not_lose_other_projects(tmp_path):
56
+ config = tmp_path / "desktop.json"
57
+ projects = [tmp_path / f"project-{i}" for i in range(4)]
58
+ with ThreadPoolExecutor(max_workers=4) as pool:
59
+ results = list(
60
+ pool.map(lambda project: desktop.connection(project, config=config), projects)
61
+ )
62
+ assert set(json.loads(config.read_text())["mcpServers"]) == {
63
+ result["server_name"] for result in results
64
+ }
65
+ assert all(desktop.checks(project)[0]["ok"] for project in projects)
66
+
67
+
68
+ def test_desktop_receipt_failure_rolls_back_config(project, tmp_path, monkeypatch):
69
+ config = tmp_path / "desktop.json"
70
+ config.write_text('{"preferences":{"keep":true}}')
71
+ before = config.read_bytes()
72
+ real_write = desktop.atomic_write
73
+
74
+ def fail_receipt(path, content):
75
+ if path.name == "claude-desktop.json":
76
+ raise OSError("simulated receipt disk failure")
77
+ real_write(path, content)
78
+
79
+ monkeypatch.setattr(desktop, "atomic_write", fail_receipt)
80
+ with pytest.raises(OSError):
81
+ desktop.connection(project, config=config)
82
+ assert config.read_bytes() == before
83
+
84
+
85
+ def test_desktop_windows_store_detection_and_ambiguity(tmp_path, monkeypatch):
86
+ monkeypatch.setattr(desktop.sys, "platform", "win32")
87
+ monkeypatch.setenv("APPDATA", str(tmp_path / "roaming"))
88
+ monkeypatch.setenv("LOCALAPPDATA", str(tmp_path / "local"))
89
+ packaged = (
90
+ tmp_path
91
+ / "local/Packages/Claude_pzs8sxrjxfjjc/LocalCache/Roaming/Claude/claude_desktop_config.json"
92
+ )
93
+ packaged.parent.mkdir(parents=True)
94
+ packaged.write_text("{}")
95
+ assert desktop.config_path() == packaged
96
+ regular = tmp_path / "roaming/Claude/claude_desktop_config.json"
97
+ regular.parent.mkdir(parents=True)
98
+ regular.write_text("{}")
99
+ with pytest.raises(ValidationError, match="Multiple"):
100
+ desktop.config_path()
101
+
102
+
103
+ def test_desktop_cli_and_invalid_config(project, tmp_path, capsys):
104
+ config = tmp_path / "desktop.json"
105
+ prefix = ["--project", str(project)]
106
+ assert main(prefix + ["connect", "claude-desktop", "--config", str(config)]) == 0
107
+ assert json.loads(capsys.readouterr().out)["connected"]
108
+ assert main(prefix + ["disconnect", "claude-desktop"]) == 0
109
+ config.write_text('{"mcpServers":[]}')
110
+ with pytest.raises(ValidationError):
111
+ desktop.connection(project, config=config)
112
+
113
+
114
+ def test_disconnect_without_receipt_does_not_discover_or_touch_config(project, monkeypatch):
115
+ monkeypatch.setattr(desktop, "config_path", lambda: pytest.fail("must not discover config"))
116
+ assert desktop.connection(project, remove=True) == {
117
+ "connected": False,
118
+ "changed": False,
119
+ "state_retained": True,
120
+ }
@@ -1442,7 +1442,7 @@ wheels = [
1442
1442
 
1443
1443
  [[package]]
1444
1444
  name = "skillstate-kit"
1445
- version = "0.1.1"
1445
+ version = "0.1.2"
1446
1446
  source = { editable = "." }
1447
1447
  dependencies = [
1448
1448
  { name = "jsonschema" },
File without changes