hypernote 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. hypernote-0.2.0/.github/workflows/release.yml +161 -0
  2. {hypernote-0.1.2 → hypernote-0.2.0}/.gitignore +1 -0
  3. hypernote-0.2.0/AGENTS.md +188 -0
  4. hypernote-0.2.0/CHANGELOG.md +97 -0
  5. {hypernote-0.1.2 → hypernote-0.2.0}/PKG-INFO +39 -8
  6. {hypernote-0.1.2 → hypernote-0.2.0}/README.md +38 -7
  7. hypernote-0.2.0/SKILL.md +183 -0
  8. hypernote-0.2.0/dev/README.md +29 -0
  9. hypernote-0.2.0/dev/cli-agent-ergonomics-rollout.md +69 -0
  10. hypernote-0.2.0/dev/current-architecture.md +85 -0
  11. hypernote-0.2.0/dev/module-map.md +32 -0
  12. {hypernote-0.1.2 → hypernote-0.2.0}/dev/testing-and-verification.md +1 -1
  13. hypernote-0.2.0/docs/README.md +22 -0
  14. {hypernote-0.1.2 → hypernote-0.2.0}/docs/browser-regression-spec.md +27 -1
  15. hypernote-0.2.0/docs/cli.md +119 -0
  16. {hypernote-0.1.2 → hypernote-0.2.0}/docs/getting-started.md +30 -0
  17. hypernote-0.2.0/docs/runtime-model.md +84 -0
  18. hypernote-0.2.0/docs/sdk.md +114 -0
  19. {hypernote-0.1.2 → hypernote-0.2.0}/pyproject.toml +5 -1
  20. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/cli/main.py +804 -51
  21. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/execution_orchestrator.py +79 -2
  22. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/runtime_manager.py +41 -3
  23. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/sdk.py +387 -27
  24. hypernote-0.2.0/src/hypernote/server/extension.py +259 -0
  25. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/server/handlers.py +119 -7
  26. hypernote-0.2.0/src/hypernote/server/subshell.py +395 -0
  27. hypernote-0.2.0/tests/test_browser_regression.py +386 -0
  28. hypernote-0.2.0/tests/test_cli.py +1157 -0
  29. {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_live_server.py +24 -0
  30. {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_runtime_manager.py +22 -1
  31. {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_sdk.py +60 -0
  32. hypernote-0.2.0/tests/test_subshell.py +360 -0
  33. {hypernote-0.1.2 → hypernote-0.2.0}/uv.lock +1 -1
  34. hypernote-0.1.2/.github/workflows/release.yml +0 -87
  35. hypernote-0.1.2/AGENTS.md +0 -144
  36. hypernote-0.1.2/CHANGELOG.md +0 -46
  37. hypernote-0.1.2/SKILL.md +0 -61
  38. hypernote-0.1.2/dev/README.md +0 -23
  39. hypernote-0.1.2/dev/current-architecture.md +0 -30
  40. hypernote-0.1.2/dev/module-map.md +0 -27
  41. hypernote-0.1.2/docs/README.md +0 -15
  42. hypernote-0.1.2/docs/cli.md +0 -62
  43. hypernote-0.1.2/docs/runtime-model.md +0 -39
  44. hypernote-0.1.2/docs/sdk.md +0 -82
  45. hypernote-0.1.2/hypernote/server/extension.py +0 -156
  46. hypernote-0.1.2/tests/test_browser_regression.py +0 -207
  47. hypernote-0.1.2/tests/test_cli.py +0 -530
  48. {hypernote-0.1.2 → hypernote-0.2.0}/CLAUDE.md +0 -0
  49. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/__init__.py +0 -0
  50. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/actor_ledger.py +0 -0
  51. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/cli/__init__.py +0 -0
  52. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/errors.py +0 -0
  53. {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/server/__init__.py +0 -0
  54. {hypernote-0.1.2 → hypernote-0.2.0}/tests/__init__.py +0 -0
  55. {hypernote-0.1.2 → hypernote-0.2.0}/tests/conftest.py +0 -0
  56. {hypernote-0.1.2 → hypernote-0.2.0}/tests/helpers.py +0 -0
  57. {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_actor_ledger.py +0 -0
@@ -0,0 +1,161 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: "Version to release (e.g., 0.1.3)"
8
+ required: true
9
+ type: string
10
+ publish_to_pypi:
11
+ description: "Publish to PyPI"
12
+ required: true
13
+ default: true
14
+ type: boolean
15
+ create_draft:
16
+ description: "Create as draft release"
17
+ required: false
18
+ default: false
19
+ type: boolean
20
+
21
+ permissions:
22
+ contents: write
23
+
24
+ jobs:
25
+ validate-inputs:
26
+ runs-on: ubuntu-latest
27
+ outputs:
28
+ version: ${{ steps.validate.outputs.version }}
29
+ steps:
30
+ - name: Validate version format
31
+ id: validate
32
+ run: |
33
+ VERSION="${{ inputs.version }}"
34
+ if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?$ ]]; then
35
+ echo "❌ Invalid version format: $VERSION"
36
+ echo "Expected semantic version (e.g., 0.1.3, 0.2.0-alpha.1)"
37
+ exit 1
38
+ fi
39
+ echo "✅ Version format is valid"
40
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
41
+
42
+ release:
43
+ needs: validate-inputs
44
+ runs-on: ubuntu-latest
45
+ outputs:
46
+ version: ${{ steps.version_update.outputs.version }}
47
+ steps:
48
+ - uses: actions/checkout@v6
49
+ with:
50
+ fetch-depth: 0
51
+ token: ${{ secrets.GITHUB_TOKEN }}
52
+
53
+ - uses: astral-sh/setup-uv@v7
54
+ with:
55
+ enable-cache: true
56
+
57
+ - name: Update version and create commit
58
+ id: version_update
59
+ env:
60
+ VERSION: ${{ needs.validate-inputs.outputs.version }}
61
+ run: |
62
+ sed -i -E "0,/^version = \".*\"/s//version = \"$VERSION\"/" pyproject.toml
63
+
64
+ if ! grep -q "version = \"$VERSION\"" pyproject.toml; then
65
+ echo "❌ Failed to update version in pyproject.toml"
66
+ exit 1
67
+ fi
68
+
69
+ echo "✅ Version updated to $VERSION"
70
+
71
+ git config user.name "github-actions[bot]"
72
+ git config user.email "github-actions[bot]@users.noreply.github.com"
73
+
74
+ if ! git diff --quiet pyproject.toml; then
75
+ uv lock
76
+ git add pyproject.toml uv.lock
77
+ git commit -m "chore: bump version to v$VERSION"
78
+ CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
79
+ git push origin "$CURRENT_BRANCH"
80
+ echo "✅ Version commit pushed"
81
+ fi
82
+
83
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
84
+
85
+ - name: Create and push tag
86
+ env:
87
+ VERSION: ${{ steps.version_update.outputs.version }}
88
+ run: |
89
+ TAG="v$VERSION"
90
+ if git tag -l | grep -q "^$TAG$"; then
91
+ git tag -d "$TAG" || true
92
+ git push origin ":refs/tags/$TAG" || true
93
+ fi
94
+ git tag -a "$TAG" -m "Release $TAG"
95
+ git push origin "$TAG"
96
+ echo "✅ Created and pushed tag $TAG"
97
+
98
+ - name: Build package
99
+ run: |
100
+ rm -rf dist/ build/ *.egg-info/
101
+ uv build
102
+ if [ ! -f dist/*.whl ] || [ ! -f dist/*.tar.gz ]; then
103
+ echo "❌ Build artifacts not found"
104
+ exit 1
105
+ fi
106
+ echo "✅ Package built"
107
+ ls -la dist/
108
+
109
+ - name: Verify package
110
+ run: |
111
+ uv run --isolated --no-project --with dist/*.whl python -c "import hypernote; print('ok')"
112
+ echo "✅ Package verified"
113
+
114
+ - uses: actions/upload-artifact@v6
115
+ with:
116
+ name: dist-${{ steps.version_update.outputs.version }}
117
+ path: dist/*
118
+ if-no-files-found: error
119
+
120
+ - name: Run tests
121
+ run: |
122
+ uv run --extra dev playwright install --with-deps chromium
123
+ uv run --extra dev python -m pytest -q
124
+
125
+ - name: Create GitHub Release
126
+ env:
127
+ GH_TOKEN: ${{ github.token }}
128
+ run: |
129
+ TAG="v${{ steps.version_update.outputs.version }}"
130
+ if gh release view "$TAG" >/dev/null 2>&1; then
131
+ gh release upload "$TAG" dist/* --clobber
132
+ else
133
+ gh release create "$TAG" dist/* \
134
+ --generate-notes \
135
+ --verify-tag \
136
+ ${{ inputs.create_draft && '--draft' || '' }}
137
+ fi
138
+
139
+ - name: Summary
140
+ run: |
141
+ echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
142
+ echo "- **Version:** v${{ steps.version_update.outputs.version }}" >> $GITHUB_STEP_SUMMARY
143
+ echo "- **PyPI:** ${{ inputs.publish_to_pypi }}" >> $GITHUB_STEP_SUMMARY
144
+ echo "- **Draft:** ${{ inputs.create_draft }}" >> $GITHUB_STEP_SUMMARY
145
+
146
+ publish-pypi:
147
+ needs: release
148
+ if: ${{ inputs.publish_to_pypi }}
149
+ runs-on: ubuntu-latest
150
+ steps:
151
+ - uses: actions/download-artifact@v5
152
+ with:
153
+ name: dist-${{ needs.release.outputs.version }}
154
+ path: dist/
155
+
156
+ - uses: astral-sh/setup-uv@v7
157
+
158
+ - name: Publish to PyPI
159
+ env:
160
+ UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
161
+ run: uv publish
@@ -18,3 +18,4 @@ lib/
18
18
  .jupyter/
19
19
  .agent-repl/
20
20
  tmp/
21
+ vscode-extension/out/
@@ -0,0 +1,188 @@
1
+ # Hypernote
2
+
3
+ Notebook-first execution system built on top of Jupyter shared documents
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ uv sync --extra dev
9
+ uv run hypernote
10
+ uv run hypernote --help
11
+ uv run hypernote setup serve
12
+ uv run hypernote setup doctor
13
+ uv run hypernote create tmp/demo.ipynb
14
+ uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
15
+ uv run hypernote status tmp/demo.ipynb --full
16
+ uv run python -m pytest -q
17
+ uv run ruff check src/hypernote tests
18
+ ```
19
+
20
+ ## Architecture
21
+
22
+ Jupyter owns notebook truth:
23
+
24
+ - `.ipynb` persistence
25
+ - shared YDoc document state
26
+ - kernel and session primitives
27
+ - notebook rendering in JupyterLab
28
+
29
+ Hypernote owns a thin control plane:
30
+
31
+ - public SDK in [src/hypernote/sdk.py](src/hypernote/sdk.py)
32
+ - public errors in [src/hypernote/errors.py](src/hypernote/errors.py)
33
+ - agent-first CLI in [src/hypernote/cli/main.py](src/hypernote/cli/main.py)
34
+ - execution orchestration and shared-document mutation in [src/hypernote/execution_orchestrator.py](src/hypernote/execution_orchestrator.py)
35
+ - runtime ownership in [src/hypernote/runtime_manager.py](src/hypernote/runtime_manager.py)
36
+ - HTTP handlers in [src/hypernote/server/handlers.py](src/hypernote/server/handlers.py)
37
+ - Jupyter extension wiring in [src/hypernote/server/extension.py](src/hypernote/server/extension.py)
38
+ - ephemeral job and attribution ledger in [src/hypernote/actor_ledger.py](src/hypernote/actor_ledger.py)
39
+ - subshell-aware execute/interrupt/restart in [src/hypernote/server/subshell.py](src/hypernote/server/subshell.py)
40
+ - optional VS Code embedding surface in [vscode-extension/src/extension.ts](vscode-extension/src/extension.ts)
41
+
42
+ Core rule: notebook edits and execution must operate on one logical document truth whether JupyterLab is closed, already open, or opened mid-run.
43
+
44
+ Lifecycle rule: notebook contents and outputs persist through Jupyter's `.ipynb` model, but Hypernote's runtime state, job records, and cell attribution are intentionally in-memory and notebook-scoped.
45
+
46
+ Concurrent-actor rule: JupyterLab and Hypernote share one notebook session and one kernel. Hypernote-driven cells run in an ipykernel subshell so the kernel's main shell stays responsive to native Lab actions. Hypernote's extension overrides `/api/kernels/{id}/interrupt` and `/api/kernels/{id}/restart` so Lab's Stop and Restart toolbar buttons reach the subshell-routed cell or perform the right cleanup. See [dev/current-architecture.md](dev/current-architecture.md) for the full mechanism.
47
+
48
+ ## Shipped Surface
49
+
50
+ ### SDK
51
+
52
+ - `hypernote.connect(path, create=False)`
53
+ - `Notebook`, `CellCollection`, `CellHandle`, `Runtime`, `Job`
54
+ - `nb.run(...)`, `nb.run_all()`, `nb.restart()`, `nb.interrupt()`
55
+ - `nb.snapshot()`, `nb.status()`, `nb.diff(...)`
56
+
57
+ ### CLI
58
+
59
+ - `hypernote` — live workspace dashboard with hints
60
+ - `create`
61
+ - `ix`
62
+ - `exec`
63
+ - `edit`
64
+ - `run-all`
65
+ - `restart`
66
+ - `restart-run-all`
67
+ - `interrupt`
68
+ - `status`
69
+ - `diff`
70
+ - `cat`
71
+ - `job ...`
72
+ - `runtime ...`
73
+ - `setup doctor`
74
+ - `setup serve`
75
+
76
+ Default CLI contract:
77
+
78
+ - bare `hypernote` shows live workspace state and next-step hints
79
+ - TTY: concise human-readable progress
80
+ - non-TTY: one compact final JSON result
81
+ - explicit streaming only through `--watch` or `--stream-json`
82
+ - summary-first read payloads should come from SDK-backed observation helpers, not CLI-only formatting rules
83
+ - `setup serve` is the default local bootstrap path for a Hypernote-enabled Jupyter server
84
+ - `setup doctor --path PATH` is the preferred first diagnostic when server reachability,
85
+ kernelspec selection, or runtime mismatch is unclear
86
+
87
+ ## Rules
88
+
89
+ - Terminology: when the user says "our system", treat that as the maintained project-operating surface, including `AGENTS.md`, `SKILL.md`, `docs/`, `dev/`, tests, and other shared guidance or verification artifacts around the code.
90
+ - SDK first. CLI behavior should come from the SDK, not duplicate raw HTTP semantics.
91
+ - When CLI and SDK both need compact observation behavior, define the summary/truncation/focused-read logic in the SDK and let the CLI adapt it.
92
+ - Shared logic needs one owner. When a helper or shaping rule moves into the SDK or another shared layer, delete the old copies instead of letting multiple versions drift.
93
+ - One truth. Do not reintroduce a contents-vs-YDoc split for notebook reads or writes.
94
+ - Runtime creation must honor the requested kernel first, otherwise notebook metadata
95
+ `kernelspec.name`, otherwise `python3`.
96
+ - Keep control-plane state ephemeral. Do not add durable job history unless the product explicitly needs it.
97
+ - Our system is part of done. After every meaningful change, update the relevant parts of `AGENTS.md`, `SKILL.md`, `docs/`, `dev/`, tests, and adjacent shared project guidance so they stay in sync with implementation.
98
+ - Keep adapters thin. CLI, JupyterLab, and tests should reuse shared contracts instead of re-encoding notebook behavior.
99
+ - Treat output and API shapes as contracts. Feature variants should preserve the same top-level envelope and field semantics unless there is a deliberate, documented exception.
100
+ - Normalize boundary inputs early. If upstream payloads can arrive in more than one valid shape, accept and normalize them at the adapter boundary rather than assuming a single representation.
101
+ - Prefer unique notebook paths in tests and demos. Browser tests must also use unique JupyterLab workspace URLs.
102
+ - Keep `tmp/` disposable. Durable notes belong in `docs/` or `dev/`, not `tmp/`.
103
+
104
+ ## Read These First
105
+
106
+ - [SKILL.md](SKILL.md)
107
+ - [docs/README.md](docs/README.md)
108
+ - [dev/README.md](dev/README.md)
109
+
110
+ ## If You Are Editing...
111
+
112
+ ### `vscode-extension/*`
113
+
114
+ - keep the extension decoupled from Hypernote-specific notebook semantics
115
+ - prefer embedding JupyterLab over recreating notebook behavior in VS Code
116
+ - if the extension launches Jupyter itself, keep that process local, explicit, and easy to inspect
117
+ - update [docs/vscode-extension.md](docs/vscode-extension.md)
118
+ - update [dev/vscode-extension.md](dev/vscode-extension.md)
119
+
120
+ ### `src/hypernote/sdk.py` or `src/hypernote/errors.py`
121
+
122
+ - preserve the notebook-first public object model
123
+ - keep public enums and errors stable
124
+ - prefer adding reusable observation helpers on `NotebookStatus` / `CellStatus` over adding CLI-only shaping logic
125
+ - update [docs/sdk.md](docs/sdk.md)
126
+
127
+ ### `src/hypernote/cli/main.py`
128
+
129
+ - keep non-TTY output compact by default
130
+ - keep bare `hypernote` as the live dashboard view
131
+ - preserve `ix` as the happy-path command
132
+ - preserve summary-first `status` and compact `cat` with contextual hints
133
+ - prefer rendering SDK observation helpers over introducing new CLI-only data shaping
134
+ - keep streaming explicit in non-TTY mode
135
+ - update [docs/cli.md](docs/cli.md)
136
+
137
+ ### `src/hypernote/execution_orchestrator.py`, `src/hypernote/runtime_manager.py`, or `src/hypernote/server/*`
138
+
139
+ - preserve the single-truth shared-document path
140
+ - verify open-tab and late-open behavior still hold
141
+ - update [dev/current-architecture.md](dev/current-architecture.md)
142
+ - if browser-visible behavior changes, update [docs/browser-regression-spec.md](docs/browser-regression-spec.md)
143
+
144
+ ### `tests/*`
145
+
146
+ - prefer the narrowest test that proves the behavior
147
+ - preserve coverage for:
148
+ - SDK shape
149
+ - CLI output contract
150
+ - live server behavior
151
+ - browser regression for streaming and late-open correctness
152
+ - for contract-heavy changes, add invariant coverage for:
153
+ - default and focused variants
154
+ - empty and failure states
155
+ - alternate valid input shapes from upstream payloads
156
+ - parity between real helpers and any fake/test-double implementations
157
+
158
+ ## Verification
159
+
160
+ Install guidance:
161
+
162
+ - `uv sync`
163
+ - base Hypernote runtime/server usage
164
+ - `uv sync --extra lab`
165
+ - adds the collaborative JupyterLab bundle
166
+ - `uv sync --extra dev`
167
+ - adds local development, lint, test, and browser-validation tooling
168
+
169
+ Minimum checks for most changes:
170
+
171
+ ```bash
172
+ uv run ruff check src/hypernote tests
173
+ uv run python -m pytest -q
174
+ ```
175
+
176
+ When browser or live-server behavior changes, also use:
177
+
178
+ ```bash
179
+ HYPERNOTE_INTEGRATION=1 uv run python -m pytest -q tests/test_live_server.py
180
+ uv run python -m pytest -q tests/test_browser_regression.py
181
+ ```
182
+
183
+ Before opening or updating a PR for a cross-surface change, do a short contract pass:
184
+
185
+ - check that sibling command variants still share one consistent envelope
186
+ - check that aggregate field names still match their exact semantics
187
+ - check that docs and hints only mention shipped commands and flags
188
+ - check that moved logic no longer has stale copies in adapters or tests
@@ -0,0 +1,97 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## Unreleased
6
+
7
+ ## 0.2.0 - 2026-05-07
8
+
9
+ Native JupyterLab as a first-class concurrent actor: open a notebook
10
+ mid-run and see streaming output, click Stop and the cell terminates,
11
+ click Restart and the kernel comes back ready. Plus the package now ships
12
+ in PyPA src layout and an experimental VS Code extension.
13
+
14
+ ### Added
15
+
16
+ - subshell-routed kernel execution (JEP 91 / ipykernel 7+): Hypernote sends `execute_request` with a `subshell_id` so the kernel's main shell stays free to answer concurrent clients (e.g. JupyterLab) — opening a notebook mid-run now renders cells immediately and continues to stream output without waiting for the running cell
17
+ - subshell-aware `POST /api/kernels/{id}/interrupt` override: JupyterLab's Stop button (and `nb.interrupt()`) now terminates a Hypernote-driven cell, raising `KeyboardInterrupt` in the subshell thread via a main-shell `PyThreadState_SetAsyncExc` injection. Falls back to default SIGINT for non-Hypernote-driven kernels.
18
+ - subshell- and nbmodel-aware `POST /api/kernels/{id}/restart` override: JupyterLab's Restart button now leaves the kernel ready to run new cells. Hypernote evicts nbmodel's stale per-kernel client and worker, and clears its cached subshell id, so the next execute rebuilds against the fresh kernel.
19
+ - new browser regression tests for Lab Stop and Lab Restart against subshell-routed cells; new real-kernel unit tests for subshell creation, routing, interrupt latency, and restart cleanup.
20
+
21
+ ### Changed
22
+
23
+ - package layout migrated to `src/hypernote/` (PyPA src layout). `pyproject.toml` now configures `[tool.hatch.build.targets.wheel] packages = ["src/hypernote"]` and `[tool.ruff] src = ["src", "tests"]`. The `hypernote` import name is unchanged — `import hypernote` continues to work.
24
+ - release workflow switched from tag-triggered to `workflow_dispatch` — run `gh workflow run release.yml -f version=X.Y.Z` to release
25
+
26
+ ### Notes
27
+
28
+ - subshell routing requires ipykernel 7+ (IPython kernels). Other kernels fall back to the main shell — late-open during a long-running cell will block the JupyterLab UI for those kernels and the subshell-targeted interrupt becomes a no-op (override falls through to SIGINT, which works on the main shell).
29
+ - `PyThreadState_SetAsyncExc`-based interrupt cannot terminate a thread inside a long blocking C call without GIL release (e.g. `requests.get` with no timeout). The `KeyboardInterrupt` only fires once control returns to Python. The interrupt snippet falls back to `os.kill(pid, SIGINT)` internally if the subshell thread cannot be found, so user-visible "Stop did nothing" cases degrade to default SIGINT behavior rather than silent failure.
30
+
31
+ ## 0.1.3 - 2026-04-03
32
+
33
+ Cross-repo runtime hardening and agent ergonomics.
34
+
35
+ ### Added
36
+
37
+ - `hypernote setup serve` — bootstraps a Hypernote-enabled Jupyter server with all required extensions
38
+ - `hypernote setup doctor --path PATH` — reports notebook kernelspec, live runtime kernel, resolved launcher, and warns on mismatches
39
+ - `hypernote create --empty` — removes any default cells Jupyter auto-inserts so notebooks start clean
40
+ - batch `ix` output now includes `cells_inserted`, `cells_total`, `cells_remaining`, `halt_reason`, and `last_processed_cell_id` on early halt
41
+ - timeout errors now surface job id, last known status, and recovery hints pointing to `job get` and `cat`
42
+ - runtime kernel mismatch detection — clear error when a live runtime's kernel doesn't match notebook metadata, with guidance to restart
43
+
44
+ ### Changed
45
+
46
+ - execution now resolves kernels as: explicit override > notebook metadata `kernelspec.name` > `python3`
47
+ - `RuntimeManager.ensure_room()` rejects silent reuse when a live room exists with a different kernel name
48
+ - removed all hardcoded local paths from project markdown files — links are now repo-relative
49
+ - SKILL.md rewritten: iterative `ix → observe → ix` is the primary workflow, heredoc/stdin documented for multi-line cells, server lifecycle section added, cross-repo setup simplified to `uv add hypernote --dev`
50
+
51
+ ### Notes
52
+
53
+ - `--cells-file` batch mode is now documented as a convenience for known-good sequences, not the default workflow
54
+ - the recommended cross-repo pattern is now: install hypernote in the target repo, not `uv run --with`
55
+
56
+ ## 0.1.1 - 2026-04-02
57
+
58
+ Patch release focused on release automation hardening.
59
+
60
+ ### Changed
61
+
62
+ - updated the GitHub release workflow to newer official action majors where available
63
+ - replaced the third-party GitHub release action with the `gh` CLI in release automation
64
+ - fixed the release workflow to install Playwright browser binaries before running browser tests
65
+ - fixed the release workflow to run tests with the `dev` extra installed
66
+ - fixed the PyPI publish step to use token-only `uv publish` authentication
67
+
68
+ ### Notes
69
+
70
+ - package code is unchanged from `0.1.0`
71
+ - this release exists to verify and stabilize the automated release path
72
+
73
+ ## 0.1.0 - 2026-04-02
74
+
75
+ Initial public release.
76
+
77
+ ### Added
78
+
79
+ - notebook-first Python SDK built around `Notebook`, `CellCollection`, `CellHandle`, `Runtime`, and `Job`
80
+ - agent-first CLI with `create`, `ix`, `exec`, `edit`, `run-all`, `restart`, `interrupt`, `status`, `diff`, `cat`, `job`, and `runtime` flows
81
+ - Jupyter server extension with narrow Hypernote REST handlers
82
+ - notebook-scoped runtime lifecycle with attach, detach, recovery, stop, and GC
83
+ - headless execution flow over Jupyter shared documents and `jupyter-server-nbmodel`
84
+ - job polling and `input()` round-trip support for long-running or interactive execution
85
+ - live-server and browser regression tests for late-open, persistence, and shared-document correctness
86
+ - project and developer docs for the runtime model, SDK, CLI, and release workflow
87
+
88
+ ### Changed
89
+
90
+ - aligned the control plane around an explicitly ephemeral lifecycle
91
+ - moved job tracking and cell attribution to an in-memory notebook-scoped ledger
92
+ - removed the SQLite dependency and any implied durable job history
93
+
94
+ ### Notes
95
+
96
+ - Jupyter owns durable notebook contents and outputs in `.ipynb`
97
+ - Hypernote owns ephemeral runtime state, jobs, and attribution
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypernote
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Thin control plane for Jupyter notebook execution with jobs, attribution, and runtime lifecycle
5
5
  Project-URL: Homepage, https://github.com/gilad-rubin/hypernote
6
6
  Project-URL: Repository, https://github.com/gilad-rubin/hypernote
@@ -33,9 +33,10 @@ Description-Content-Type: text/markdown
33
33
 
34
34
  ## What it ships
35
35
 
36
- - notebook-first SDK in `hypernote/sdk.py`
37
- - agent-first CLI in `hypernote/cli/main.py`
36
+ - notebook-first SDK in `src/hypernote/sdk.py`
37
+ - agent-first CLI in `src/hypernote/cli/main.py`
38
38
  - Jupyter server extension for execution and runtime control
39
+ - experimental VS Code extension in `vscode-extension/` for embedding JupyterLab in VS Code
39
40
  - notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
40
41
  - job polling and `input()` round-trips for headless execution
41
42
  - live-server and browser regression coverage for shared-document behavior
@@ -45,11 +46,16 @@ Description-Content-Type: text/markdown
45
46
  ```bash
46
47
  uv sync
47
48
  uv run hypernote --help
49
+ uv run hypernote setup serve
50
+ uv run hypernote setup doctor
48
51
  uv run hypernote create tmp/demo.ipynb
49
52
  uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
50
53
  uv run hypernote status tmp/demo.ipynb --full
51
54
  ```
52
55
 
56
+ For another repo's environment, install Hypernote there (`uv add hypernote --dev`) and run
57
+ the same bootstrap command from that repo.
58
+
53
59
  ## Install tiers
54
60
 
55
61
  - `hypernote`
@@ -86,12 +92,29 @@ Hypernote owns:
86
92
  - actor attribution
87
93
  - SDK, CLI, and thin REST handlers
88
94
 
95
+ ## Design discipline
96
+
97
+ - shared behavior should have one owner, usually the SDK for agent-facing observation rules
98
+ - command and payload variants should preserve one contract unless a difference is explicit and documented
99
+ - adapters should normalize valid upstream shape differences at the boundary
100
+ - tests should cover invariants across variants, not only the main workflow
101
+
89
102
  ## Documentation
90
103
 
91
- - [Getting Started](/Users/giladrubin/python_workspace/hypernote/docs/getting-started.md)
92
- - [CLI Reference](/Users/giladrubin/python_workspace/hypernote/docs/cli.md)
93
- - [SDK Reference](/Users/giladrubin/python_workspace/hypernote/docs/sdk.md)
94
- - [Runtime Model](/Users/giladrubin/python_workspace/hypernote/docs/runtime-model.md)
104
+ - [Getting Started](docs/getting-started.md)
105
+ - [CLI Reference](docs/cli.md)
106
+ - [SDK Reference](docs/sdk.md)
107
+ - [Runtime Model](docs/runtime-model.md)
108
+ - [VS Code Extension](docs/vscode-extension.md)
109
+
110
+ ## VS Code
111
+
112
+ The repository now includes a minimal VS Code extension under `vscode-extension/`.
113
+
114
+ - It embeds JupyterLab inside a VS Code custom editor or panel.
115
+ - It can reuse an existing Jupyter server via settings.
116
+ - If no server is reachable, it can start a managed local `jupyter lab` process.
117
+ - It stays decoupled from Hypernote-specific UI so Hypernote can connect to the same server separately.
95
118
 
96
119
  ## Verification
97
120
 
@@ -102,6 +125,14 @@ uv sync --extra dev
102
125
  ```
103
126
 
104
127
  ```bash
105
- uv run ruff check hypernote tests
128
+ uv run ruff check src/hypernote tests
106
129
  uv run python -m pytest -q
107
130
  ```
131
+
132
+ Extension build:
133
+
134
+ ```bash
135
+ cd vscode-extension
136
+ npm install
137
+ npm run compile
138
+ ```
@@ -7,9 +7,10 @@
7
7
 
8
8
  ## What it ships
9
9
 
10
- - notebook-first SDK in `hypernote/sdk.py`
11
- - agent-first CLI in `hypernote/cli/main.py`
10
+ - notebook-first SDK in `src/hypernote/sdk.py`
11
+ - agent-first CLI in `src/hypernote/cli/main.py`
12
12
  - Jupyter server extension for execution and runtime control
13
+ - experimental VS Code extension in `vscode-extension/` for embedding JupyterLab in VS Code
13
14
  - notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
14
15
  - job polling and `input()` round-trips for headless execution
15
16
  - live-server and browser regression coverage for shared-document behavior
@@ -19,11 +20,16 @@
19
20
  ```bash
20
21
  uv sync
21
22
  uv run hypernote --help
23
+ uv run hypernote setup serve
24
+ uv run hypernote setup doctor
22
25
  uv run hypernote create tmp/demo.ipynb
23
26
  uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
24
27
  uv run hypernote status tmp/demo.ipynb --full
25
28
  ```
26
29
 
30
+ For another repo's environment, install Hypernote there (`uv add hypernote --dev`) and run
31
+ the same bootstrap command from that repo.
32
+
27
33
  ## Install tiers
28
34
 
29
35
  - `hypernote`
@@ -60,12 +66,29 @@ Hypernote owns:
60
66
  - actor attribution
61
67
  - SDK, CLI, and thin REST handlers
62
68
 
69
+ ## Design discipline
70
+
71
+ - shared behavior should have one owner, usually the SDK for agent-facing observation rules
72
+ - command and payload variants should preserve one contract unless a difference is explicit and documented
73
+ - adapters should normalize valid upstream shape differences at the boundary
74
+ - tests should cover invariants across variants, not only the main workflow
75
+
63
76
  ## Documentation
64
77
 
65
- - [Getting Started](/Users/giladrubin/python_workspace/hypernote/docs/getting-started.md)
66
- - [CLI Reference](/Users/giladrubin/python_workspace/hypernote/docs/cli.md)
67
- - [SDK Reference](/Users/giladrubin/python_workspace/hypernote/docs/sdk.md)
68
- - [Runtime Model](/Users/giladrubin/python_workspace/hypernote/docs/runtime-model.md)
78
+ - [Getting Started](docs/getting-started.md)
79
+ - [CLI Reference](docs/cli.md)
80
+ - [SDK Reference](docs/sdk.md)
81
+ - [Runtime Model](docs/runtime-model.md)
82
+ - [VS Code Extension](docs/vscode-extension.md)
83
+
84
+ ## VS Code
85
+
86
+ The repository now includes a minimal VS Code extension under `vscode-extension/`.
87
+
88
+ - It embeds JupyterLab inside a VS Code custom editor or panel.
89
+ - It can reuse an existing Jupyter server via settings.
90
+ - If no server is reachable, it can start a managed local `jupyter lab` process.
91
+ - It stays decoupled from Hypernote-specific UI so Hypernote can connect to the same server separately.
69
92
 
70
93
  ## Verification
71
94
 
@@ -76,6 +99,14 @@ uv sync --extra dev
76
99
  ```
77
100
 
78
101
  ```bash
79
- uv run ruff check hypernote tests
102
+ uv run ruff check src/hypernote tests
80
103
  uv run python -m pytest -q
81
104
  ```
105
+
106
+ Extension build:
107
+
108
+ ```bash
109
+ cd vscode-extension
110
+ npm install
111
+ npm run compile
112
+ ```