hypernote 0.2.0__tar.gz → 0.3.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.
- hypernote-0.3.0/.github/workflows/release.yml +236 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/AGENTS.md +11 -13
- {hypernote-0.2.0 → hypernote-0.3.0}/CHANGELOG.md +22 -0
- hypernote-0.3.0/CONTEXT.md +38 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/PKG-INFO +14 -37
- {hypernote-0.2.0 → hypernote-0.3.0}/README.md +10 -32
- {hypernote-0.2.0 → hypernote-0.3.0}/SKILL.md +9 -9
- {hypernote-0.2.0 → hypernote-0.3.0}/dev/README.md +5 -7
- {hypernote-0.2.0 → hypernote-0.3.0}/dev/current-architecture.md +4 -2
- hypernote-0.3.0/dev/module-map.md +29 -0
- hypernote-0.3.0/dev/release.md +135 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/dev/testing-and-verification.md +1 -3
- {hypernote-0.2.0 → hypernote-0.3.0}/docs/README.md +0 -1
- {hypernote-0.2.0 → hypernote-0.3.0}/docs/browser-regression-spec.md +5 -5
- {hypernote-0.2.0 → hypernote-0.3.0}/docs/cli.md +5 -4
- {hypernote-0.2.0 → hypernote-0.3.0}/docs/getting-started.md +11 -9
- {hypernote-0.2.0 → hypernote-0.3.0}/docs/sdk.md +9 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/pyproject.toml +4 -6
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/cli/main.py +150 -13
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/execution_orchestrator.py +9 -78
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/sdk.py +17 -1
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/server/extension.py +38 -9
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/server/handlers.py +10 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_cli.py +170 -3
- hypernote-0.3.0/tests/test_package_metadata.py +27 -0
- hypernote-0.3.0/tests/test_server_extension.py +83 -0
- hypernote-0.3.0/tests/test_shared_notebook_accessor.py +47 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/uv.lock +8 -10
- hypernote-0.2.0/.github/workflows/release.yml +0 -161
- hypernote-0.2.0/dev/module-map.md +0 -32
- {hypernote-0.2.0 → hypernote-0.3.0}/.gitignore +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/CLAUDE.md +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/dev/cli-agent-ergonomics-rollout.md +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/docs/runtime-model.md +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/__init__.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/actor_ledger.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/cli/__init__.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/errors.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/runtime_manager.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/server/__init__.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/src/hypernote/server/subshell.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/__init__.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/conftest.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/helpers.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_actor_ledger.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_browser_regression.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_live_server.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_runtime_manager.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_sdk.py +0 -0
- {hypernote-0.2.0 → hypernote-0.3.0}/tests/test_subshell.py +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: "Version to release (e.g., 0.3.0)"
|
|
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
|
+
push:
|
|
21
|
+
branches:
|
|
22
|
+
- master
|
|
23
|
+
paths:
|
|
24
|
+
- "CHANGELOG.md"
|
|
25
|
+
- "pyproject.toml"
|
|
26
|
+
- "uv.lock"
|
|
27
|
+
- ".github/workflows/release.yml"
|
|
28
|
+
|
|
29
|
+
permissions:
|
|
30
|
+
contents: write
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
resolve-version:
|
|
34
|
+
if: ${{ github.event_name != 'push' || github.actor != 'github-actions[bot]' }}
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
outputs:
|
|
37
|
+
version: ${{ steps.resolve.outputs.version }}
|
|
38
|
+
publish_to_pypi: ${{ steps.resolve.outputs.publish_to_pypi }}
|
|
39
|
+
create_draft: ${{ steps.resolve.outputs.create_draft }}
|
|
40
|
+
should_release: ${{ steps.resolve.outputs.should_release }}
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v6
|
|
43
|
+
with:
|
|
44
|
+
fetch-depth: 0
|
|
45
|
+
|
|
46
|
+
- name: Resolve release version
|
|
47
|
+
id: resolve
|
|
48
|
+
env:
|
|
49
|
+
INPUT_VERSION: ${{ inputs.version }}
|
|
50
|
+
INPUT_PUBLISH_TO_PYPI: ${{ inputs.publish_to_pypi }}
|
|
51
|
+
INPUT_CREATE_DRAFT: ${{ inputs.create_draft }}
|
|
52
|
+
run: |
|
|
53
|
+
VERSION="$INPUT_VERSION"
|
|
54
|
+
if [ -z "$VERSION" ]; then
|
|
55
|
+
VERSION="$(python - <<'PY'
|
|
56
|
+
import tomllib
|
|
57
|
+
from pathlib import Path
|
|
58
|
+
|
|
59
|
+
print(tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"])
|
|
60
|
+
PY
|
|
61
|
+
)"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?$ ]]; then
|
|
65
|
+
echo "❌ Invalid version format: $VERSION"
|
|
66
|
+
echo "Expected semantic version (e.g., 0.3.0, 0.3.0-alpha.1)"
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
git fetch --tags --force
|
|
71
|
+
TAG="v$VERSION"
|
|
72
|
+
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
|
|
73
|
+
if [ "$GITHUB_EVENT_NAME" = "push" ] && [ "${GITHUB_RUN_ATTEMPT:-1}" = "1" ]; then
|
|
74
|
+
echo "ℹ️ $TAG already exists; nothing to release."
|
|
75
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
76
|
+
echo "publish_to_pypi=false" >> "$GITHUB_OUTPUT"
|
|
77
|
+
echo "create_draft=false" >> "$GITHUB_OUTPUT"
|
|
78
|
+
echo "should_release=false" >> "$GITHUB_OUTPUT"
|
|
79
|
+
exit 0
|
|
80
|
+
fi
|
|
81
|
+
echo "ℹ️ $TAG already exists; continuing because this is a rerun/recovery attempt."
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
echo "✅ Version format is valid: $VERSION"
|
|
85
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
86
|
+
echo "publish_to_pypi=${INPUT_PUBLISH_TO_PYPI:-true}" >> "$GITHUB_OUTPUT"
|
|
87
|
+
echo "create_draft=${INPUT_CREATE_DRAFT:-false}" >> "$GITHUB_OUTPUT"
|
|
88
|
+
echo "should_release=true" >> "$GITHUB_OUTPUT"
|
|
89
|
+
|
|
90
|
+
release:
|
|
91
|
+
needs: resolve-version
|
|
92
|
+
if: ${{ needs.resolve-version.outputs.should_release == 'true' }}
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
outputs:
|
|
95
|
+
version: ${{ needs.resolve-version.outputs.version }}
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/checkout@v6
|
|
98
|
+
with:
|
|
99
|
+
fetch-depth: 0
|
|
100
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
101
|
+
|
|
102
|
+
- uses: astral-sh/setup-uv@v7
|
|
103
|
+
with:
|
|
104
|
+
enable-cache: true
|
|
105
|
+
|
|
106
|
+
- name: Ensure release version is checked in
|
|
107
|
+
env:
|
|
108
|
+
VERSION: ${{ needs.resolve-version.outputs.version }}
|
|
109
|
+
run: |
|
|
110
|
+
CURRENT_VERSION="$(python - <<'PY'
|
|
111
|
+
import tomllib
|
|
112
|
+
from pathlib import Path
|
|
113
|
+
|
|
114
|
+
print(tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"])
|
|
115
|
+
PY
|
|
116
|
+
)"
|
|
117
|
+
|
|
118
|
+
if [ "$CURRENT_VERSION" = "$VERSION" ]; then
|
|
119
|
+
echo "✅ pyproject.toml already declares $VERSION"
|
|
120
|
+
exit 0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]; then
|
|
124
|
+
echo "❌ pyproject.toml declares $CURRENT_VERSION, expected $VERSION"
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
sed -i -E "0,/^version = \".*\"/s//version = \"$VERSION\"/" pyproject.toml
|
|
129
|
+
|
|
130
|
+
if ! grep -q "version = \"$VERSION\"" pyproject.toml; then
|
|
131
|
+
echo "❌ Failed to update version in pyproject.toml"
|
|
132
|
+
exit 1
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
git config user.name "github-actions[bot]"
|
|
136
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
137
|
+
uv lock
|
|
138
|
+
git add pyproject.toml uv.lock
|
|
139
|
+
git commit -m "chore: bump version to v$VERSION"
|
|
140
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
141
|
+
git push origin "$CURRENT_BRANCH"
|
|
142
|
+
echo "✅ Version commit pushed"
|
|
143
|
+
|
|
144
|
+
- name: Build package
|
|
145
|
+
run: |
|
|
146
|
+
rm -rf dist/ build/ *.egg-info/
|
|
147
|
+
uv build
|
|
148
|
+
if [ ! -f dist/*.whl ] || [ ! -f dist/*.tar.gz ]; then
|
|
149
|
+
echo "❌ Build artifacts not found"
|
|
150
|
+
exit 1
|
|
151
|
+
fi
|
|
152
|
+
echo "✅ Package built"
|
|
153
|
+
ls -la dist/
|
|
154
|
+
|
|
155
|
+
- name: Verify package
|
|
156
|
+
run: |
|
|
157
|
+
uv run --isolated --no-project --with dist/*.whl python -c "import hypernote; print('ok')"
|
|
158
|
+
echo "✅ Package verified"
|
|
159
|
+
|
|
160
|
+
- uses: actions/upload-artifact@v6
|
|
161
|
+
with:
|
|
162
|
+
name: dist-${{ needs.resolve-version.outputs.version }}
|
|
163
|
+
path: dist/*
|
|
164
|
+
if-no-files-found: error
|
|
165
|
+
|
|
166
|
+
- name: Run tests
|
|
167
|
+
run: |
|
|
168
|
+
uv run --extra dev playwright install --with-deps chromium
|
|
169
|
+
uv run --extra dev python -m pytest -q
|
|
170
|
+
|
|
171
|
+
- name: Create and push tag
|
|
172
|
+
env:
|
|
173
|
+
VERSION: ${{ needs.resolve-version.outputs.version }}
|
|
174
|
+
run: |
|
|
175
|
+
TAG="v$VERSION"
|
|
176
|
+
git config user.name "github-actions[bot]"
|
|
177
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
178
|
+
git fetch --tags --force
|
|
179
|
+
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
|
|
180
|
+
TAG_TARGET="$(git rev-list -n 1 "$TAG")"
|
|
181
|
+
HEAD_SHA="$(git rev-parse HEAD)"
|
|
182
|
+
if [ "$TAG_TARGET" = "$HEAD_SHA" ]; then
|
|
183
|
+
echo "✅ $TAG already points at $HEAD_SHA; continuing."
|
|
184
|
+
exit 0
|
|
185
|
+
fi
|
|
186
|
+
echo "❌ $TAG points at $TAG_TARGET, not current HEAD $HEAD_SHA. Refusing to retag."
|
|
187
|
+
exit 1
|
|
188
|
+
fi
|
|
189
|
+
git tag -a "$TAG" -m "Release $TAG"
|
|
190
|
+
git push origin "$TAG"
|
|
191
|
+
echo "✅ Created and pushed tag $TAG"
|
|
192
|
+
|
|
193
|
+
- name: Create GitHub Release
|
|
194
|
+
env:
|
|
195
|
+
GH_TOKEN: ${{ github.token }}
|
|
196
|
+
CREATE_DRAFT: ${{ needs.resolve-version.outputs.create_draft }}
|
|
197
|
+
run: |
|
|
198
|
+
TAG="v${{ needs.resolve-version.outputs.version }}"
|
|
199
|
+
DRAFT_FLAG=""
|
|
200
|
+
if [ "$CREATE_DRAFT" = "true" ]; then
|
|
201
|
+
DRAFT_FLAG="--draft"
|
|
202
|
+
fi
|
|
203
|
+
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
204
|
+
gh release upload "$TAG" dist/* --clobber
|
|
205
|
+
else
|
|
206
|
+
gh release create "$TAG" dist/* \
|
|
207
|
+
--generate-notes \
|
|
208
|
+
--verify-tag \
|
|
209
|
+
$DRAFT_FLAG
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
- name: Summary
|
|
213
|
+
run: |
|
|
214
|
+
echo "## Release Summary" >> "$GITHUB_STEP_SUMMARY"
|
|
215
|
+
echo "- **Version:** v${{ needs.resolve-version.outputs.version }}" >> "$GITHUB_STEP_SUMMARY"
|
|
216
|
+
echo "- **PyPI:** ${{ needs.resolve-version.outputs.publish_to_pypi }}" >> "$GITHUB_STEP_SUMMARY"
|
|
217
|
+
echo "- **Draft:** ${{ needs.resolve-version.outputs.create_draft }}" >> "$GITHUB_STEP_SUMMARY"
|
|
218
|
+
|
|
219
|
+
publish-pypi:
|
|
220
|
+
needs:
|
|
221
|
+
- resolve-version
|
|
222
|
+
- release
|
|
223
|
+
if: ${{ needs.resolve-version.outputs.publish_to_pypi == 'true' }}
|
|
224
|
+
runs-on: ubuntu-latest
|
|
225
|
+
steps:
|
|
226
|
+
- uses: actions/download-artifact@v5
|
|
227
|
+
with:
|
|
228
|
+
name: dist-${{ needs.resolve-version.outputs.version }}
|
|
229
|
+
path: dist/
|
|
230
|
+
|
|
231
|
+
- uses: astral-sh/setup-uv@v7
|
|
232
|
+
|
|
233
|
+
- name: Publish to PyPI
|
|
234
|
+
env:
|
|
235
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
236
|
+
run: uv publish
|
|
@@ -37,7 +37,6 @@ Hypernote owns a thin control plane:
|
|
|
37
37
|
- Jupyter extension wiring in [src/hypernote/server/extension.py](src/hypernote/server/extension.py)
|
|
38
38
|
- ephemeral job and attribution ledger in [src/hypernote/actor_ledger.py](src/hypernote/actor_ledger.py)
|
|
39
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
40
|
|
|
42
41
|
Core rule: notebook edits and execution must operate on one logical document truth whether JupyterLab is closed, already open, or opened mid-run.
|
|
43
42
|
|
|
@@ -80,7 +79,7 @@ Default CLI contract:
|
|
|
80
79
|
- non-TTY: one compact final JSON result
|
|
81
80
|
- explicit streaming only through `--watch` or `--stream-json`
|
|
82
81
|
- 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
|
|
82
|
+
- `setup serve` is the default local bootstrap path for a Hypernote-enabled JupyterLab server
|
|
84
83
|
- `setup doctor --path PATH` is the preferred first diagnostic when server reachability,
|
|
85
84
|
kernelspec selection, or runtime mismatch is unclear
|
|
86
85
|
|
|
@@ -100,23 +99,17 @@ Default CLI contract:
|
|
|
100
99
|
- 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
100
|
- Prefer unique notebook paths in tests and demos. Browser tests must also use unique JupyterLab workspace URLs.
|
|
102
101
|
- Keep `tmp/` disposable. Durable notes belong in `docs/` or `dev/`, not `tmp/`.
|
|
102
|
+
- Release every version through a PR (CHANGELOG move + version bump + lockfile refresh on a `release/vX.Y.Z` branch), never via direct push to master. The full process is in [dev/release.md](dev/release.md).
|
|
103
103
|
|
|
104
104
|
## Read These First
|
|
105
105
|
|
|
106
106
|
- [SKILL.md](SKILL.md)
|
|
107
107
|
- [docs/README.md](docs/README.md)
|
|
108
108
|
- [dev/README.md](dev/README.md)
|
|
109
|
+
- [dev/release.md](dev/release.md)
|
|
109
110
|
|
|
110
111
|
## If You Are Editing...
|
|
111
112
|
|
|
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
113
|
### `src/hypernote/sdk.py` or `src/hypernote/errors.py`
|
|
121
114
|
|
|
122
115
|
- preserve the notebook-first public object model
|
|
@@ -155,14 +148,19 @@ Default CLI contract:
|
|
|
155
148
|
- alternate valid input shapes from upstream payloads
|
|
156
149
|
- parity between real helpers and any fake/test-double implementations
|
|
157
150
|
|
|
151
|
+
### `pyproject.toml` version, `CHANGELOG.md`, or `.github/workflows/release.yml`
|
|
152
|
+
|
|
153
|
+
- always use the PR-based release process in [dev/release.md](dev/release.md)
|
|
154
|
+
- do not push release-prep commits directly to master, even for a one-line version bump
|
|
155
|
+
- before opening the release PR, confirm `git ls-tree origin/master` shows every file mentioned in the new CHANGELOG section — local-only work must not be claimed in the changelog
|
|
156
|
+
- if you change the release workflow shape (steps, secrets, version source), update [dev/release.md](dev/release.md) in the same PR so the doc stays accurate
|
|
157
|
+
|
|
158
158
|
## Verification
|
|
159
159
|
|
|
160
160
|
Install guidance:
|
|
161
161
|
|
|
162
162
|
- `uv sync`
|
|
163
|
-
-
|
|
164
|
-
- `uv sync --extra lab`
|
|
165
|
-
- adds the collaborative JupyterLab bundle
|
|
163
|
+
- Hypernote's default JupyterLab integration stack
|
|
166
164
|
- `uv sync --extra dev`
|
|
167
165
|
- adds local development, lint, test, and browser-validation tooling
|
|
168
166
|
|
|
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.3.0 - 2026-05-10
|
|
8
|
+
|
|
9
|
+
Hypernote is now a JupyterLab-first integration: the default install carries the
|
|
10
|
+
collaboration/docprovider stack, `setup serve` opens Lab by default, and
|
|
11
|
+
`setup doctor` can distinguish API reachability from shared-document and Lab
|
|
12
|
+
frontend health.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Hypernote is now packaged and documented as a JupyterLab-first integration:
|
|
17
|
+
the default install includes JupyterLab collaboration support, `setup serve`
|
|
18
|
+
opens Lab by default, `setup doctor` reports the shared-document stack and
|
|
19
|
+
duplicate local servers, and cell-state operations require the shared
|
|
20
|
+
document path instead of falling back to contents-manager edits.
|
|
21
|
+
|
|
22
|
+
### Notes
|
|
23
|
+
|
|
24
|
+
- correction: the 0.2.0 headline mentions "an experimental VS Code extension" but the
|
|
25
|
+
`vscode-extension/` work was never committed and did not ship in the 0.2.0 artifact.
|
|
26
|
+
Documentation referring to the VS Code extension has been removed from `README.md`,
|
|
27
|
+
`AGENTS.md`, `SKILL.md`, `docs/README.md`, `dev/README.md`, and `dev/module-map.md`.
|
|
28
|
+
|
|
7
29
|
## 0.2.0 - 2026-05-07
|
|
8
30
|
|
|
9
31
|
Native JupyterLab as a first-class concurrent actor: open a notebook
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Hypernote
|
|
2
|
+
|
|
3
|
+
Hypernote coordinates notebook execution through a Hypernote-enabled JupyterLab
|
|
4
|
+
server so agents and humans can work against one notebook truth.
|
|
5
|
+
|
|
6
|
+
## Language
|
|
7
|
+
|
|
8
|
+
**Shared Document**:
|
|
9
|
+
The server-side notebook document that all Hypernote operations use as the live notebook truth.
|
|
10
|
+
_Avoid_: file-only notebook truth
|
|
11
|
+
|
|
12
|
+
**Hypernote JupyterLab Server**:
|
|
13
|
+
A JupyterLab server launched or verified with Hypernote's required server and collaboration extensions.
|
|
14
|
+
_Avoid_: plain Jupyter server, separate agent server
|
|
15
|
+
|
|
16
|
+
**Open Lab Tab**:
|
|
17
|
+
A browser tab viewing a notebook through the Hypernote JupyterLab Server.
|
|
18
|
+
_Avoid_: separate Lab server, plain Lab tab
|
|
19
|
+
|
|
20
|
+
**Agent Automation**:
|
|
21
|
+
CLI or SDK notebook work performed through the Hypernote JupyterLab Server, whether an Open Lab Tab currently exists.
|
|
22
|
+
_Avoid_: separate runtime mode
|
|
23
|
+
|
|
24
|
+
## Relationships
|
|
25
|
+
|
|
26
|
+
- A **Hypernote JupyterLab Server** owns the **Shared Document**.
|
|
27
|
+
- An **Open Lab Tab** and **Agent Automation** must attach to the same **Hypernote JupyterLab Server**.
|
|
28
|
+
- **Agent Automation** does not require an **Open Lab Tab**, but it still requires the **Hypernote JupyterLab Server**.
|
|
29
|
+
|
|
30
|
+
## Example Dialogue
|
|
31
|
+
|
|
32
|
+
> **Dev:** "Can agents run notebooks without JupyterLab?"
|
|
33
|
+
> **Domain expert:** "No separate mode: agents use the **Hypernote JupyterLab Server** even if nobody has an **Open Lab Tab**."
|
|
34
|
+
|
|
35
|
+
## Flagged Ambiguities
|
|
36
|
+
|
|
37
|
+
- Agent work without an **Open Lab Tab** was previously described as a separate product mode; resolved: Hypernote only distinguishes whether an **Open Lab Tab** exists.
|
|
38
|
+
- "Jupyter server" was used broadly; resolved: the supported product server is a **Hypernote JupyterLab Server**.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypernote
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.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
|
|
@@ -8,25 +8,24 @@ Project-URL: Issues, https://github.com/gilad-rubin/hypernote/issues
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Requires-Dist: click>=8.0
|
|
10
10
|
Requires-Dist: httpx>=0.27
|
|
11
|
+
Requires-Dist: jupyter-collaboration>=3.0
|
|
12
|
+
Requires-Dist: jupyter-docprovider>=2.0
|
|
11
13
|
Requires-Dist: jupyter-server-nbmodel>=0.1
|
|
12
14
|
Requires-Dist: jupyter-server-ydoc>=1.0
|
|
13
15
|
Requires-Dist: jupyter-server>=2.0
|
|
16
|
+
Requires-Dist: jupyterlab>=4.0
|
|
14
17
|
Requires-Dist: pycrdt>=0.12
|
|
15
18
|
Provides-Extra: dev
|
|
16
|
-
Requires-Dist: jupyter-collaboration>=3.0; extra == 'dev'
|
|
17
|
-
Requires-Dist: jupyterlab>=4.0; extra == 'dev'
|
|
18
19
|
Requires-Dist: playwright>=1.40; extra == 'dev'
|
|
19
20
|
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
20
21
|
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
21
22
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
22
23
|
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
23
|
-
Provides-Extra: lab
|
|
24
|
-
Requires-Dist: jupyter-collaboration>=3.0; extra == 'lab'
|
|
25
24
|
Description-Content-Type: text/markdown
|
|
26
25
|
|
|
27
26
|
# Hypernote
|
|
28
27
|
|
|
29
|
-
- **
|
|
28
|
+
- **JupyterLab-first** - Hypernote is a thin execution control plane for a Hypernote-enabled JupyterLab server.
|
|
30
29
|
- **One notebook truth** - notebook edits, execution, and late-open JupyterLab views all operate on the same logical document.
|
|
31
30
|
- **Agent-first surface** - the Python SDK is primary, and the CLI is a thin shell over it.
|
|
32
31
|
- **Ephemeral control plane** - Jupyter owns durable `.ipynb` contents and outputs; Hypernote owns in-memory runtimes, jobs, and attribution.
|
|
@@ -36,9 +35,9 @@ Description-Content-Type: text/markdown
|
|
|
36
35
|
- notebook-first SDK in `src/hypernote/sdk.py`
|
|
37
36
|
- agent-first CLI in `src/hypernote/cli/main.py`
|
|
38
37
|
- Jupyter server extension for execution and runtime control
|
|
39
|
-
-
|
|
38
|
+
- subshell-routed execute, interrupt, and restart so JupyterLab stays usable while Hypernote is running cells
|
|
40
39
|
- notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
|
|
41
|
-
- job polling and `input()` round-trips for
|
|
40
|
+
- job polling and `input()` round-trips for agent automation without requiring an open Lab tab
|
|
42
41
|
- live-server and browser regression coverage for shared-document behavior
|
|
43
42
|
|
|
44
43
|
## Quick start
|
|
@@ -56,23 +55,18 @@ uv run hypernote status tmp/demo.ipynb --full
|
|
|
56
55
|
For another repo's environment, install Hypernote there (`uv add hypernote --dev`) and run
|
|
57
56
|
the same bootstrap command from that repo.
|
|
58
57
|
|
|
59
|
-
## Install
|
|
58
|
+
## Install
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- use this when you want the full collaborative JupyterLab experience
|
|
67
|
-
- `hypernote[dev]`
|
|
68
|
-
- adds test, lint, browser, and local dev tooling
|
|
69
|
-
- use this for local development and CI
|
|
60
|
+
The default install includes the JupyterLab integration stack Hypernote needs:
|
|
61
|
+
JupyterLab, shared-document support, server-side notebook execution, and the
|
|
62
|
+
collaboration/docprovider frontend packages.
|
|
63
|
+
|
|
64
|
+
Use `hypernote[dev]` only for local development and CI tooling.
|
|
70
65
|
|
|
71
66
|
Examples:
|
|
72
67
|
|
|
73
68
|
```bash
|
|
74
69
|
uv sync
|
|
75
|
-
uv sync --extra lab
|
|
76
70
|
uv sync --extra dev
|
|
77
71
|
```
|
|
78
72
|
|
|
@@ -105,16 +99,7 @@ Hypernote owns:
|
|
|
105
99
|
- [CLI Reference](docs/cli.md)
|
|
106
100
|
- [SDK Reference](docs/sdk.md)
|
|
107
101
|
- [Runtime Model](docs/runtime-model.md)
|
|
108
|
-
- [
|
|
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.
|
|
102
|
+
- [Browser Regression Spec](docs/browser-regression-spec.md)
|
|
118
103
|
|
|
119
104
|
## Verification
|
|
120
105
|
|
|
@@ -128,11 +113,3 @@ uv sync --extra dev
|
|
|
128
113
|
uv run ruff check src/hypernote tests
|
|
129
114
|
uv run python -m pytest -q
|
|
130
115
|
```
|
|
131
|
-
|
|
132
|
-
Extension build:
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
cd vscode-extension
|
|
136
|
-
npm install
|
|
137
|
-
npm run compile
|
|
138
|
-
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Hypernote
|
|
2
2
|
|
|
3
|
-
- **
|
|
3
|
+
- **JupyterLab-first** - Hypernote is a thin execution control plane for a Hypernote-enabled JupyterLab server.
|
|
4
4
|
- **One notebook truth** - notebook edits, execution, and late-open JupyterLab views all operate on the same logical document.
|
|
5
5
|
- **Agent-first surface** - the Python SDK is primary, and the CLI is a thin shell over it.
|
|
6
6
|
- **Ephemeral control plane** - Jupyter owns durable `.ipynb` contents and outputs; Hypernote owns in-memory runtimes, jobs, and attribution.
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
- notebook-first SDK in `src/hypernote/sdk.py`
|
|
11
11
|
- agent-first CLI in `src/hypernote/cli/main.py`
|
|
12
12
|
- Jupyter server extension for execution and runtime control
|
|
13
|
-
-
|
|
13
|
+
- subshell-routed execute, interrupt, and restart so JupyterLab stays usable while Hypernote is running cells
|
|
14
14
|
- notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
|
|
15
|
-
- job polling and `input()` round-trips for
|
|
15
|
+
- job polling and `input()` round-trips for agent automation without requiring an open Lab tab
|
|
16
16
|
- live-server and browser regression coverage for shared-document behavior
|
|
17
17
|
|
|
18
18
|
## Quick start
|
|
@@ -30,23 +30,18 @@ uv run hypernote status tmp/demo.ipynb --full
|
|
|
30
30
|
For another repo's environment, install Hypernote there (`uv add hypernote --dev`) and run
|
|
31
31
|
the same bootstrap command from that repo.
|
|
32
32
|
|
|
33
|
-
## Install
|
|
33
|
+
## Install
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- use this when you want the full collaborative JupyterLab experience
|
|
41
|
-
- `hypernote[dev]`
|
|
42
|
-
- adds test, lint, browser, and local dev tooling
|
|
43
|
-
- use this for local development and CI
|
|
35
|
+
The default install includes the JupyterLab integration stack Hypernote needs:
|
|
36
|
+
JupyterLab, shared-document support, server-side notebook execution, and the
|
|
37
|
+
collaboration/docprovider frontend packages.
|
|
38
|
+
|
|
39
|
+
Use `hypernote[dev]` only for local development and CI tooling.
|
|
44
40
|
|
|
45
41
|
Examples:
|
|
46
42
|
|
|
47
43
|
```bash
|
|
48
44
|
uv sync
|
|
49
|
-
uv sync --extra lab
|
|
50
45
|
uv sync --extra dev
|
|
51
46
|
```
|
|
52
47
|
|
|
@@ -79,16 +74,7 @@ Hypernote owns:
|
|
|
79
74
|
- [CLI Reference](docs/cli.md)
|
|
80
75
|
- [SDK Reference](docs/sdk.md)
|
|
81
76
|
- [Runtime Model](docs/runtime-model.md)
|
|
82
|
-
- [
|
|
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.
|
|
77
|
+
- [Browser Regression Spec](docs/browser-regression-spec.md)
|
|
92
78
|
|
|
93
79
|
## Verification
|
|
94
80
|
|
|
@@ -102,11 +88,3 @@ uv sync --extra dev
|
|
|
102
88
|
uv run ruff check src/hypernote tests
|
|
103
89
|
uv run python -m pytest -q
|
|
104
90
|
```
|
|
105
|
-
|
|
106
|
-
Extension build:
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
cd vscode-extension
|
|
110
|
-
npm install
|
|
111
|
-
npm run compile
|
|
112
|
-
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hypernote
|
|
3
|
-
description: Work against Hypernote's notebook-first SDK and agent-first CLI. Use this when an agent needs to create notebooks, insert or edit cells, run code
|
|
3
|
+
description: Work against Hypernote's notebook-first SDK and agent-first CLI. Use this when an agent needs to create notebooks, insert or edit cells, run code without an open Lab tab, inspect notebook status or diffs, or verify JupyterLab attach/streaming behavior.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hypernote
|
|
@@ -23,7 +23,7 @@ Hypernote CLI requires two things:
|
|
|
23
23
|
uv add hypernote --dev
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
2. **A running
|
|
26
|
+
2. **A running Hypernote-enabled JupyterLab server.**
|
|
27
27
|
See "Server lifecycle" below.
|
|
28
28
|
|
|
29
29
|
Once both are in place, all commands are just `uv run hypernote ...`.
|
|
@@ -44,11 +44,12 @@ Verify it points to your repo's `.venv/bin/python`. If it does, the server is go
|
|
|
44
44
|
**If no server is running, start one in the background:**
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
uv run hypernote setup serve &
|
|
47
|
+
uv run hypernote setup serve --no-browser &
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
`setup serve` is a foreground process — run it in the background so your terminal stays
|
|
51
|
-
available. The default address is `http://127.0.0.1:8888`.
|
|
51
|
+
available. The default address is `http://127.0.0.1:8888`. Omit `--no-browser`
|
|
52
|
+
when you want setup to open JupyterLab immediately.
|
|
52
53
|
|
|
53
54
|
**If the server is running but `default_kernel` points to the wrong Python** (e.g., a
|
|
54
55
|
different repo's `.venv`), stop the old server and start a new one with `setup serve`
|
|
@@ -60,7 +61,7 @@ if it's backgrounded, find its pid with `lsof -ti :8888` and kill it.
|
|
|
60
61
|
**If port 8888 is taken**, use a different port and point all commands at it:
|
|
61
62
|
|
|
62
63
|
```bash
|
|
63
|
-
uv run hypernote setup serve --port 8889 &
|
|
64
|
+
uv run hypernote setup serve --port 8889 --no-browser &
|
|
64
65
|
uv run hypernote --server http://127.0.0.1:8889 setup doctor
|
|
65
66
|
```
|
|
66
67
|
|
|
@@ -69,7 +70,7 @@ uv run hypernote --server http://127.0.0.1:8889 setup doctor
|
|
|
69
70
|
```bash
|
|
70
71
|
uv run hypernote # live workspace dashboard and hints
|
|
71
72
|
uv run hypernote setup doctor # check for existing server
|
|
72
|
-
uv run hypernote setup serve &
|
|
73
|
+
uv run hypernote setup serve --no-browser & # only if no server is running
|
|
73
74
|
uv run hypernote create tmp/demo.ipynb --empty
|
|
74
75
|
uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22'
|
|
75
76
|
uv run hypernote status tmp/demo.ipynb --full
|
|
@@ -149,7 +150,7 @@ know exactly where to resume. Cells after the halt point were never inserted int
|
|
|
149
150
|
7. Start with `hypernote` itself when you need workspace context and the next best action.
|
|
150
151
|
8. Use `--stream-json` only when you plan to watch the process; otherwise it wastes context.
|
|
151
152
|
9. Start the server with `hypernote setup serve` instead of hand-writing Jupyter flags.
|
|
152
|
-
10. Skip large rich outputs such as `graph.visualize()` in
|
|
153
|
+
10. Skip large rich outputs such as `graph.visualize()` in agent automation unless the visualization is the point of the run.
|
|
153
154
|
11. Use unique notebook paths in tests and demos.
|
|
154
155
|
12. Move durable notes into `docs/` or `dev/`; keep `tmp/` disposable.
|
|
155
156
|
13. Treat Hypernote jobs, runtime state, and cell attribution as ephemeral coordination state, not durable history.
|
|
@@ -163,7 +164,6 @@ know exactly where to resume. Cells after the halt point were never inserted int
|
|
|
163
164
|
1. Read [AGENTS.md](AGENTS.md).
|
|
164
165
|
2. Check the current public surface in [docs/cli.md](docs/cli.md) and [docs/sdk.md](docs/sdk.md).
|
|
165
166
|
3. If browser-visible execution behavior changes, check [docs/browser-regression-spec.md](docs/browser-regression-spec.md).
|
|
166
|
-
4. If the VS Code embedding experience changes, check [docs/vscode-extension.md](docs/vscode-extension.md).
|
|
167
167
|
|
|
168
168
|
## Verification
|
|
169
169
|
|
|
@@ -173,7 +173,7 @@ Install the right tier first:
|
|
|
173
173
|
uv sync --extra dev
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
-
Use `uv sync` for
|
|
176
|
+
Use `uv sync` for Hypernote's default JupyterLab integration stack.
|
|
177
177
|
|
|
178
178
|
Then run:
|
|
179
179
|
|
|
@@ -9,15 +9,13 @@ Read these first:
|
|
|
9
9
|
- [Current Architecture](current-architecture.md)
|
|
10
10
|
- [Module Map](module-map.md)
|
|
11
11
|
- [Testing and Verification](testing-and-verification.md)
|
|
12
|
+
- [Release Process](release.md)
|
|
12
13
|
- [CLI Agent Ergonomics Rollout](cli-agent-ergonomics-rollout.md)
|
|
13
|
-
- [VS Code Extension Notes](vscode-extension.md)
|
|
14
14
|
|
|
15
|
-
Release
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- PyPI auth comes from the GitHub Actions secret `PYPI_API_TOKEN`
|
|
20
|
-
- see [release.yml](../.github/workflows/release.yml)
|
|
15
|
+
Releases: see [Release Process](release.md). Always via PR — release-prep
|
|
16
|
+
commits go through review like feature work. Workflow lives at
|
|
17
|
+
[`.github/workflows/release.yml`](../.github/workflows/release.yml); PyPI
|
|
18
|
+
auth via the `PYPI_API_TOKEN` GitHub Actions secret.
|
|
21
19
|
|
|
22
20
|
Rules:
|
|
23
21
|
|
|
@@ -18,10 +18,12 @@ Jupyter shared document + kernel/session primitives
|
|
|
18
18
|
|
|
19
19
|
- The SDK is the public semantic center.
|
|
20
20
|
- The CLI is a thin shell over the SDK.
|
|
21
|
-
- `setup serve` is the CLI bootstrap path for starting a local Hypernote-enabled
|
|
21
|
+
- `setup serve` is the CLI bootstrap path for starting a local Hypernote-enabled JupyterLab server.
|
|
22
22
|
- Notebook reads and writes must go through the shared-document path.
|
|
23
23
|
- Execution must resolve cell source from the same document model the UI sees.
|
|
24
|
-
- JupyterLab is
|
|
24
|
+
- JupyterLab is the supported integration environment. Opening a Lab tab is optional,
|
|
25
|
+
but Hypernote still runs through the Hypernote-enabled JupyterLab server and shared
|
|
26
|
+
document path.
|
|
25
27
|
|
|
26
28
|
## Important consequences
|
|
27
29
|
|