hypernote 0.1.3__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.
- hypernote-0.2.0/.github/workflows/release.yml +161 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/AGENTS.md +40 -13
- {hypernote-0.1.3 → hypernote-0.2.0}/CHANGELOG.md +18 -4
- {hypernote-0.1.3 → hypernote-0.2.0}/PKG-INFO +11 -4
- {hypernote-0.1.3 → hypernote-0.2.0}/README.md +10 -3
- {hypernote-0.1.3 → hypernote-0.2.0}/SKILL.md +23 -12
- hypernote-0.2.0/dev/README.md +29 -0
- hypernote-0.2.0/dev/cli-agent-ergonomics-rollout.md +69 -0
- hypernote-0.2.0/dev/current-architecture.md +85 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/dev/module-map.md +8 -8
- {hypernote-0.1.3 → hypernote-0.2.0}/dev/testing-and-verification.md +1 -1
- {hypernote-0.1.3 → hypernote-0.2.0}/docs/README.md +3 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/docs/browser-regression-spec.md +27 -1
- {hypernote-0.1.3 → hypernote-0.2.0}/docs/cli.md +38 -4
- hypernote-0.2.0/docs/runtime-model.md +84 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/docs/sdk.md +28 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/pyproject.toml +5 -1
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/cli/main.py +619 -48
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/execution_orchestrator.py +53 -1
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/runtime_manager.py +5 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/sdk.py +336 -23
- hypernote-0.2.0/src/hypernote/server/extension.py +259 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/server/handlers.py +92 -0
- hypernote-0.2.0/src/hypernote/server/subshell.py +395 -0
- hypernote-0.2.0/tests/test_browser_regression.py +386 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/test_cli.py +420 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/test_sdk.py +32 -0
- hypernote-0.2.0/tests/test_subshell.py +360 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/uv.lock +1 -1
- hypernote-0.1.3/.github/workflows/release.yml +0 -87
- hypernote-0.1.3/dev/README.md +0 -24
- hypernote-0.1.3/dev/current-architecture.md +0 -34
- hypernote-0.1.3/docs/runtime-model.md +0 -50
- hypernote-0.1.3/hypernote/server/extension.py +0 -156
- hypernote-0.1.3/tests/test_browser_regression.py +0 -207
- {hypernote-0.1.3 → hypernote-0.2.0}/.gitignore +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/CLAUDE.md +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/docs/getting-started.md +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/__init__.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/actor_ledger.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/cli/__init__.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/errors.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0/src}/hypernote/server/__init__.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/__init__.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/conftest.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/helpers.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/test_actor_ledger.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/test_live_server.py +0 -0
- {hypernote-0.1.3 → hypernote-0.2.0}/tests/test_runtime_manager.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
|
|
@@ -6,6 +6,7 @@ Notebook-first execution system built on top of Jupyter shared documents
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
uv sync --extra dev
|
|
9
|
+
uv run hypernote
|
|
9
10
|
uv run hypernote --help
|
|
10
11
|
uv run hypernote setup serve
|
|
11
12
|
uv run hypernote setup doctor
|
|
@@ -13,7 +14,7 @@ uv run hypernote create tmp/demo.ipynb
|
|
|
13
14
|
uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
|
|
14
15
|
uv run hypernote status tmp/demo.ipynb --full
|
|
15
16
|
uv run python -m pytest -q
|
|
16
|
-
uv run ruff check hypernote tests
|
|
17
|
+
uv run ruff check src/hypernote tests
|
|
17
18
|
```
|
|
18
19
|
|
|
19
20
|
## Architecture
|
|
@@ -27,20 +28,23 @@ Jupyter owns notebook truth:
|
|
|
27
28
|
|
|
28
29
|
Hypernote owns a thin control plane:
|
|
29
30
|
|
|
30
|
-
- public SDK in [hypernote/sdk.py](hypernote/sdk.py)
|
|
31
|
-
- public errors in [hypernote/errors.py](hypernote/errors.py)
|
|
32
|
-
- agent-first CLI in [hypernote/cli/main.py](hypernote/cli/main.py)
|
|
33
|
-
- execution orchestration and shared-document mutation in [hypernote/execution_orchestrator.py](hypernote/execution_orchestrator.py)
|
|
34
|
-
- runtime ownership in [hypernote/runtime_manager.py](hypernote/runtime_manager.py)
|
|
35
|
-
- HTTP handlers in [hypernote/server/handlers.py](hypernote/server/handlers.py)
|
|
36
|
-
- Jupyter extension wiring in [hypernote/server/extension.py](hypernote/server/extension.py)
|
|
37
|
-
- ephemeral job and attribution ledger in [hypernote/actor_ledger.py](hypernote/actor_ledger.py)
|
|
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)
|
|
38
40
|
- optional VS Code embedding surface in [vscode-extension/src/extension.ts](vscode-extension/src/extension.ts)
|
|
39
41
|
|
|
40
42
|
Core rule: notebook edits and execution must operate on one logical document truth whether JupyterLab is closed, already open, or opened mid-run.
|
|
41
43
|
|
|
42
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.
|
|
43
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
|
+
|
|
44
48
|
## Shipped Surface
|
|
45
49
|
|
|
46
50
|
### SDK
|
|
@@ -52,6 +56,7 @@ Lifecycle rule: notebook contents and outputs persist through Jupyter's `.ipynb`
|
|
|
52
56
|
|
|
53
57
|
### CLI
|
|
54
58
|
|
|
59
|
+
- `hypernote` — live workspace dashboard with hints
|
|
55
60
|
- `create`
|
|
56
61
|
- `ix`
|
|
57
62
|
- `exec`
|
|
@@ -70,9 +75,11 @@ Lifecycle rule: notebook contents and outputs persist through Jupyter's `.ipynb`
|
|
|
70
75
|
|
|
71
76
|
Default CLI contract:
|
|
72
77
|
|
|
78
|
+
- bare `hypernote` shows live workspace state and next-step hints
|
|
73
79
|
- TTY: concise human-readable progress
|
|
74
80
|
- non-TTY: one compact final JSON result
|
|
75
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
|
|
76
83
|
- `setup serve` is the default local bootstrap path for a Hypernote-enabled Jupyter server
|
|
77
84
|
- `setup doctor --path PATH` is the preferred first diagnostic when server reachability,
|
|
78
85
|
kernelspec selection, or runtime mismatch is unclear
|
|
@@ -81,12 +88,16 @@ Default CLI contract:
|
|
|
81
88
|
|
|
82
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.
|
|
83
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.
|
|
84
93
|
- One truth. Do not reintroduce a contents-vs-YDoc split for notebook reads or writes.
|
|
85
94
|
- Runtime creation must honor the requested kernel first, otherwise notebook metadata
|
|
86
95
|
`kernelspec.name`, otherwise `python3`.
|
|
87
96
|
- Keep control-plane state ephemeral. Do not add durable job history unless the product explicitly needs it.
|
|
88
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.
|
|
89
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.
|
|
90
101
|
- Prefer unique notebook paths in tests and demos. Browser tests must also use unique JupyterLab workspace URLs.
|
|
91
102
|
- Keep `tmp/` disposable. Durable notes belong in `docs/` or `dev/`, not `tmp/`.
|
|
92
103
|
|
|
@@ -106,20 +117,24 @@ Default CLI contract:
|
|
|
106
117
|
- update [docs/vscode-extension.md](docs/vscode-extension.md)
|
|
107
118
|
- update [dev/vscode-extension.md](dev/vscode-extension.md)
|
|
108
119
|
|
|
109
|
-
### `hypernote/sdk.py` or `hypernote/errors.py`
|
|
120
|
+
### `src/hypernote/sdk.py` or `src/hypernote/errors.py`
|
|
110
121
|
|
|
111
122
|
- preserve the notebook-first public object model
|
|
112
123
|
- keep public enums and errors stable
|
|
124
|
+
- prefer adding reusable observation helpers on `NotebookStatus` / `CellStatus` over adding CLI-only shaping logic
|
|
113
125
|
- update [docs/sdk.md](docs/sdk.md)
|
|
114
126
|
|
|
115
|
-
### `hypernote/cli/main.py`
|
|
127
|
+
### `src/hypernote/cli/main.py`
|
|
116
128
|
|
|
117
129
|
- keep non-TTY output compact by default
|
|
130
|
+
- keep bare `hypernote` as the live dashboard view
|
|
118
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
|
|
119
134
|
- keep streaming explicit in non-TTY mode
|
|
120
135
|
- update [docs/cli.md](docs/cli.md)
|
|
121
136
|
|
|
122
|
-
### `hypernote/execution_orchestrator.py`, `hypernote/runtime_manager.py`, or `hypernote/server/*`
|
|
137
|
+
### `src/hypernote/execution_orchestrator.py`, `src/hypernote/runtime_manager.py`, or `src/hypernote/server/*`
|
|
123
138
|
|
|
124
139
|
- preserve the single-truth shared-document path
|
|
125
140
|
- verify open-tab and late-open behavior still hold
|
|
@@ -134,6 +149,11 @@ Default CLI contract:
|
|
|
134
149
|
- CLI output contract
|
|
135
150
|
- live server behavior
|
|
136
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
|
|
137
157
|
|
|
138
158
|
## Verification
|
|
139
159
|
|
|
@@ -149,7 +169,7 @@ Install guidance:
|
|
|
149
169
|
Minimum checks for most changes:
|
|
150
170
|
|
|
151
171
|
```bash
|
|
152
|
-
uv run ruff check hypernote tests
|
|
172
|
+
uv run ruff check src/hypernote tests
|
|
153
173
|
uv run python -m pytest -q
|
|
154
174
|
```
|
|
155
175
|
|
|
@@ -159,3 +179,10 @@ When browser or live-server behavior changes, also use:
|
|
|
159
179
|
HYPERNOTE_INTEGRATION=1 uv run python -m pytest -q tests/test_live_server.py
|
|
160
180
|
uv run python -m pytest -q tests/test_browser_regression.py
|
|
161
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
|
|
@@ -4,15 +4,29 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
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
|
+
|
|
7
14
|
### Added
|
|
8
15
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
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
|
|
11
25
|
|
|
12
26
|
### Notes
|
|
13
27
|
|
|
14
|
-
- the
|
|
15
|
-
-
|
|
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.
|
|
16
30
|
|
|
17
31
|
## 0.1.3 - 2026-04-03
|
|
18
32
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypernote
|
|
3
|
-
Version: 0.
|
|
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,8 +33,8 @@ 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
39
|
- experimental VS Code extension in `vscode-extension/` for embedding JupyterLab in VS Code
|
|
40
40
|
- notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
|
|
@@ -92,6 +92,13 @@ Hypernote owns:
|
|
|
92
92
|
- actor attribution
|
|
93
93
|
- SDK, CLI, and thin REST handlers
|
|
94
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
|
+
|
|
95
102
|
## Documentation
|
|
96
103
|
|
|
97
104
|
- [Getting Started](docs/getting-started.md)
|
|
@@ -118,7 +125,7 @@ uv sync --extra dev
|
|
|
118
125
|
```
|
|
119
126
|
|
|
120
127
|
```bash
|
|
121
|
-
uv run ruff check hypernote tests
|
|
128
|
+
uv run ruff check src/hypernote tests
|
|
122
129
|
uv run python -m pytest -q
|
|
123
130
|
```
|
|
124
131
|
|
|
@@ -7,8 +7,8 @@
|
|
|
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
13
|
- experimental VS Code extension in `vscode-extension/` for embedding JupyterLab in VS Code
|
|
14
14
|
- notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
|
|
@@ -66,6 +66,13 @@ Hypernote owns:
|
|
|
66
66
|
- actor attribution
|
|
67
67
|
- SDK, CLI, and thin REST handlers
|
|
68
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
|
+
|
|
69
76
|
## Documentation
|
|
70
77
|
|
|
71
78
|
- [Getting Started](docs/getting-started.md)
|
|
@@ -92,7 +99,7 @@ uv sync --extra dev
|
|
|
92
99
|
```
|
|
93
100
|
|
|
94
101
|
```bash
|
|
95
|
-
uv run ruff check hypernote tests
|
|
102
|
+
uv run ruff check src/hypernote tests
|
|
96
103
|
uv run python -m pytest -q
|
|
97
104
|
```
|
|
98
105
|
|
|
@@ -7,7 +7,11 @@ description: Work against Hypernote's notebook-first SDK and agent-first CLI. Us
|
|
|
7
7
|
|
|
8
8
|
`hypernote` is the notebook runtime surface. The SDK is the core API. The CLI is a thin shell over that SDK.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Design rule: if a compact read model, truncation rule, or focused observation flow is useful in the CLI and also generally useful to agents or other adapters, define it in the SDK first and let the CLI render it, rather than re-encoding the logic in the CLI.
|
|
11
|
+
|
|
12
|
+
Review rule: prefer finishing a feature with contract cleanup, not just feature coverage. Variants should share one envelope, aggregate names should match their exact semantics, and adapters should normalize boundary payload shapes instead of assuming one representation.
|
|
13
|
+
|
|
14
|
+
Run `uv run hypernote` for a live workspace dashboard, `uv run hypernote --help` for the current command list, and `uv run hypernote <command> --help` for exact syntax.
|
|
11
15
|
|
|
12
16
|
## Prerequisite
|
|
13
17
|
|
|
@@ -63,6 +67,7 @@ uv run hypernote --server http://127.0.0.1:8889 setup doctor
|
|
|
63
67
|
## Quick Start
|
|
64
68
|
|
|
65
69
|
```bash
|
|
70
|
+
uv run hypernote # live workspace dashboard and hints
|
|
66
71
|
uv run hypernote setup doctor # check for existing server
|
|
67
72
|
uv run hypernote setup serve & # only if no server is running
|
|
68
73
|
uv run hypernote create tmp/demo.ipynb --empty
|
|
@@ -112,14 +117,15 @@ Do not use `-s` for multi-line code. Shell quoting will corrupt newlines.
|
|
|
112
117
|
- `exec` — re-run an existing cell by id (useful after editing a failed cell)
|
|
113
118
|
- `edit` — mutate cell source or structure without executing
|
|
114
119
|
- `run-all` / `restart` / `restart-run-all` — notebook-wide execution
|
|
115
|
-
- `status` / `diff` / `cat` — inspect notebook state and outputs
|
|
120
|
+
- `status` / `diff` / `cat` — inspect notebook state and outputs with summary-first reads, filtered cells, and focused output flags
|
|
116
121
|
|
|
117
122
|
### When a cell fails
|
|
118
123
|
|
|
119
124
|
1. Read the error output from `ix`.
|
|
120
|
-
2.
|
|
121
|
-
3.
|
|
122
|
-
4.
|
|
125
|
+
2. Use `cat --cell <cell-id>` or `cat --output <cell-id>` if you need a compact view of the failure.
|
|
126
|
+
3. Fix the source with `edit replace`.
|
|
127
|
+
4. Re-run with `exec <cell-id>`.
|
|
128
|
+
5. Continue with the next `ix`.
|
|
123
129
|
|
|
124
130
|
Do not re-insert a failed cell. Edit it in place and re-execute.
|
|
125
131
|
|
|
@@ -140,12 +146,17 @@ know exactly where to resume. Cells after the halt point were never inserted int
|
|
|
140
146
|
4. Prefer the SDK and CLI over raw HTTP unless you are explicitly working on server routes.
|
|
141
147
|
5. Treat Jupyter shared documents as the source of truth. Open or closed JupyterLab tabs must not change correctness.
|
|
142
148
|
6. For agents, prefer default non-TTY JSON output unless you intentionally want background streaming.
|
|
143
|
-
7.
|
|
144
|
-
8.
|
|
145
|
-
9.
|
|
146
|
-
10.
|
|
147
|
-
11.
|
|
148
|
-
12.
|
|
149
|
+
7. Start with `hypernote` itself when you need workspace context and the next best action.
|
|
150
|
+
8. Use `--stream-json` only when you plan to watch the process; otherwise it wastes context.
|
|
151
|
+
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 headless automation unless the visualization is the point of the run.
|
|
153
|
+
11. Use unique notebook paths in tests and demos.
|
|
154
|
+
12. Move durable notes into `docs/` or `dev/`; keep `tmp/` disposable.
|
|
155
|
+
13. Treat Hypernote jobs, runtime state, and cell attribution as ephemeral coordination state, not durable history.
|
|
156
|
+
14. When changing read/inspection behavior, update the SDK observation helpers before or alongside the CLI so every adapter shares the same summary/truncation rules.
|
|
157
|
+
15. Keep command hints grounded in shipped commands and actual runtime values. Do not document or suggest a focused read flag unless it exists in the CLI.
|
|
158
|
+
16. For contract-heavy changes, test the focused variants, empty/failure states, and alternate valid payload shapes, not just the happy path.
|
|
159
|
+
17. When a helper moves into the SDK or another shared layer, remove the old CLI/test copy in the same change.
|
|
149
160
|
|
|
150
161
|
## Before You Change Behavior
|
|
151
162
|
|
|
@@ -167,6 +178,6 @@ Use `uv sync` for base runtime work and `uv sync --extra lab` when you specifica
|
|
|
167
178
|
Then run:
|
|
168
179
|
|
|
169
180
|
```bash
|
|
170
|
-
uv run ruff check hypernote tests
|
|
181
|
+
uv run ruff check src/hypernote tests
|
|
171
182
|
uv run python -m pytest -q
|
|
172
183
|
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Development Docs
|
|
2
|
+
|
|
3
|
+
This folder is internal reference for the shipped Hypernote architecture.
|
|
4
|
+
|
|
5
|
+
Public workflow docs live in `docs/`. This folder is for implementation-facing notes only.
|
|
6
|
+
|
|
7
|
+
Read these first:
|
|
8
|
+
|
|
9
|
+
- [Current Architecture](current-architecture.md)
|
|
10
|
+
- [Module Map](module-map.md)
|
|
11
|
+
- [Testing and Verification](testing-and-verification.md)
|
|
12
|
+
- [CLI Agent Ergonomics Rollout](cli-agent-ergonomics-rollout.md)
|
|
13
|
+
- [VS Code Extension Notes](vscode-extension.md)
|
|
14
|
+
|
|
15
|
+
Release path:
|
|
16
|
+
|
|
17
|
+
- trigger the release workflow from GitHub Actions UI or `gh workflow run release.yml -f version=X.Y.Z`
|
|
18
|
+
- the workflow bumps `pyproject.toml`, syncs `uv.lock`, commits, tags, builds, tests, creates a GitHub release, and publishes to PyPI
|
|
19
|
+
- PyPI auth comes from the GitHub Actions secret `PYPI_API_TOKEN`
|
|
20
|
+
- see [release.yml](../.github/workflows/release.yml)
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
|
|
24
|
+
- keep this folder small
|
|
25
|
+
- document shipped behavior, not aspirational redesigns
|
|
26
|
+
- when behavior changes, update `AGENTS.md`, `SKILL.md`, `docs/`, and `dev/` together
|
|
27
|
+
- prefer one short source of truth per principle instead of repeating long process notes across many docs
|
|
28
|
+
- use this folder for implementation discipline and architecture notes; keep public contract wording in `docs/`
|
|
29
|
+
- for cross-surface changes, write down the invariants that must stay true across variants, not just the happy-path workflow
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# CLI Agent Ergonomics Rollout
|
|
2
|
+
|
|
3
|
+
This document tracks the AXI-inspired improvements for Hypernote's CLI.
|
|
4
|
+
|
|
5
|
+
Status:
|
|
6
|
+
|
|
7
|
+
- Phase 1 is shipped and documented in the public CLI reference.
|
|
8
|
+
- Phase 2 and Phase 3 remain open.
|
|
9
|
+
|
|
10
|
+
Goals:
|
|
11
|
+
|
|
12
|
+
- reduce agent discovery turns
|
|
13
|
+
- keep default non-TTY reads compact
|
|
14
|
+
- make notebook state easier to act on without extra calls
|
|
15
|
+
- preserve JSON compatibility and the existing SDK-first CLI contract
|
|
16
|
+
|
|
17
|
+
Non-goals for now:
|
|
18
|
+
|
|
19
|
+
- replacing JSON with a custom format
|
|
20
|
+
- shell hook ambient context
|
|
21
|
+
- changing all error output conventions at once
|
|
22
|
+
|
|
23
|
+
## Phase 1 Shipped
|
|
24
|
+
|
|
25
|
+
- [x] Add contextual `hint:` lines after high-value commands.
|
|
26
|
+
- [x] Make bare `hypernote` show a live home view instead of help text.
|
|
27
|
+
- [x] Add precomputed notebook aggregates to `status`.
|
|
28
|
+
- [x] Redesign default `cat` output to be summary-first.
|
|
29
|
+
- [x] Truncate large outputs by default in agent-oriented reads.
|
|
30
|
+
- [x] Add focused read flags for notebook inspection.
|
|
31
|
+
- [x] Make empty states explicit across notebook, runtime, and job reads.
|
|
32
|
+
|
|
33
|
+
Shipped behavior:
|
|
34
|
+
|
|
35
|
+
- `hypernote` with no subcommand returns actionable live state instead of Click help
|
|
36
|
+
- `status` answers "is this notebook healthy?" from top-level fields
|
|
37
|
+
- `cat` answers "what cells are here and which one should I inspect?" without full dumps
|
|
38
|
+
- large outputs are truncated in non-TTY reads unless `--full-output` is used
|
|
39
|
+
- hints only reference shipped commands and real runtime values
|
|
40
|
+
- the compact read model is now SDK-backed so the CLI is not the only place that knows the summary/truncation rules
|
|
41
|
+
|
|
42
|
+
## Remaining Backlog
|
|
43
|
+
|
|
44
|
+
### Phase 2
|
|
45
|
+
|
|
46
|
+
- [ ] Add a one-command repair path for failed cells.
|
|
47
|
+
- [ ] Add richer recovery hints for failed, timed out, and awaiting-input jobs.
|
|
48
|
+
- [ ] Make `job get` and `runtime status` summary-first.
|
|
49
|
+
- [ ] Make `setup doctor` more decision-oriented.
|
|
50
|
+
- [ ] Flatten agent-oriented JSON output where it helps avoid deep nesting.
|
|
51
|
+
|
|
52
|
+
### Phase 3
|
|
53
|
+
|
|
54
|
+
- [ ] Add `--fields` support on read commands.
|
|
55
|
+
- [ ] Normalize `--full`, `--full-output`, and `--max-output` semantics.
|
|
56
|
+
- [ ] Add stable machine-readable error codes for JSON mode.
|
|
57
|
+
- [ ] Shorten subcommand help and make it example-led.
|
|
58
|
+
- [ ] Add concrete command examples to help output.
|
|
59
|
+
- [ ] Keep responses content-first and help-second.
|
|
60
|
+
- [ ] Include notebook-relative context in hints where possible.
|
|
61
|
+
- [ ] Consider a dedicated `home` or `dashboard` command if the bare root becomes overloaded.
|
|
62
|
+
- [ ] Consider optional ambient context hooks after core command outputs are strong.
|
|
63
|
+
- [ ] Add richer notebook health summaries for stale or mismatched runtime states.
|
|
64
|
+
|
|
65
|
+
## Deferred
|
|
66
|
+
|
|
67
|
+
- TOON or other custom output formats
|
|
68
|
+
- shell/session hook ambient context
|
|
69
|
+
- sweeping stdout/stderr contract changes
|