ipinb 0.2.0__tar.gz → 0.4.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.
- {ipinb-0.2.0 → ipinb-0.4.0}/BREAKING_CHANGES.md +14 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/CHANGELOG.md +13 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/PKG-INFO +10 -10
- {ipinb-0.2.0 → ipinb-0.4.0}/README.md +9 -9
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/architecture.md +8 -2
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/debugging.md +3 -3
- {ipinb-0.2.0/ipi/skills/notebook/references → ipinb-0.4.0/docs}/execution-and-results.md +5 -5
- {ipinb-0.2.0/ipi/skills/notebook/references → ipinb-0.4.0/docs}/kernel-environments.md +4 -4
- {ipinb-0.2.0/ipi/skills/notebook/references → ipinb-0.4.0/docs}/notebook-publishing.md +1 -1
- {ipinb-0.2.0/ipi/skills/notebook/references → ipinb-0.4.0/docs}/parallel-execution.md +2 -2
- {ipinb-0.2.0/src/ipi/resources/references → ipinb-0.4.0/docs}/rich-output.md +3 -3
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/notebook/SKILL.md +3 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/notebook/references/debugging.md +3 -3
- {ipinb-0.2.0/docs → ipinb-0.4.0/ipi/skills/notebook/references}/execution-and-results.md +5 -5
- {ipinb-0.2.0/docs → ipinb-0.4.0/ipi/skills/notebook/references}/kernel-environments.md +4 -4
- {ipinb-0.2.0/src/ipi/resources → ipinb-0.4.0/ipi/skills/notebook}/references/notebook-publishing.md +1 -1
- {ipinb-0.2.0/src/ipi/resources → ipinb-0.4.0/ipi/skills/notebook}/references/parallel-execution.md +2 -2
- {ipinb-0.2.0/docs → ipinb-0.4.0/ipi/skills/notebook/references}/rich-output.md +3 -3
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/notebook-http/SKILL.md +1 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/pyproject.toml +1 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/contract.py +0 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/ssh.py +7 -8
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/supervisor.py +13 -20
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_uv_environment.py +34 -68
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/execution_models.py +0 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/kernel.py +7 -47
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/resource_registry.py +42 -6
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/resources/notebook_http_skill.md +1 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/resources/notebook_skill.md +3 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/resources/references/debugging.md +3 -3
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/resources/references/execution-and-results.md +5 -5
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/resources/references/kernel-environments.md +4 -4
- {ipinb-0.2.0/docs → ipinb-0.4.0/src/ipi/resources/references}/notebook-publishing.md +1 -1
- {ipinb-0.2.0/docs → ipinb-0.4.0/src/ipi/resources/references}/parallel-execution.md +2 -2
- {ipinb-0.2.0/ipi/skills/notebook → ipinb-0.4.0/src/ipi/resources}/references/rich-output.md +3 -3
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/environment.py +1 -11
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/execution_server.py +9 -13
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipinb.egg-info/PKG-INFO +10 -10
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_kernel.py +29 -96
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_ssh_transport.py +54 -52
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_transport_contract.py +0 -4
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_uv_environment.py +146 -15
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_environment.py +1 -1
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_plugin_authoring_skill.py +1 -2
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_multi_project_plugins.py +4 -5
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_plugin_server_integration.py +1 -2
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_execution_registry.py +62 -15
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_execution_transports.py +3 -3
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_resource_registry.py +177 -37
- {ipinb-0.2.0 → ipinb-0.4.0}/LICENSE +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/MANIFEST.in +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/ipi-mcp-redesign.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/notebook-service-log.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/notebook-service-plan.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/performance-log.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/performance-plan.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/performance-results.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/reduce-output-tokens-log.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/autopilot/reduce-output-tokens-plan.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/releasing.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/validation/compact-output-blocks-2026-09-13.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/validation/execution-api-2026-09-10.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/validation/fastmcp4-2026-09-13.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/docs/your-first-extension.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/SKILL.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/references/authoring-guide.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/references/evaluations.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/references/source-map.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/references/testing-and-troubleshooting.md +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/templates/installed-plugin/pyproject.toml +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/templates/installed-plugin/src/example_ipi_plugin/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/templates/installed-plugin/tests/test_plugin.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/ipi/skills/developing-ipi-plugins/templates/project-plugin.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/package-lock.json +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/package.json +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/src/cell_chrome.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/src/index.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/src/intent.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/src/metadata.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/src/setup_chrome.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/style/index.css +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/tests/index.spec.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/tests/setup.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/tsconfig.json +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/tsconfig.test.json +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/jupyterlab-extension/vitest.config.ts +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/setup.cfg +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_ansi.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_dependency_metadata.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_exception_groups.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_git_provenance.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_kernel_argv.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_kernel_launcher.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_launch_gate.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_markdown.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_model_output.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_notebook_mirror.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_owner_watchdog.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_parent_process.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_platform_support.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_self_wheel.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_timing.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_toml.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/address.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/artifacts.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/local.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/master_owner.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/owned_directory.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/portable_uv.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/staging.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_transport/supervisor_protocol.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/_ynotebook_ops.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/cell_export.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/config.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/execution_backend.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/jupyter_server.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/labextensions/@ipi/notebook-extension/package.json +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/labextensions/@ipi/notebook-extension/static/40.5dddbc48f9255afab0d7.js +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/labextensions/@ipi/notebook-extension/static/665.890acd7e2a9ea1a043aa.js +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/labextensions/@ipi/notebook-extension/static/remoteEntry.aa9e35c0f1b6fe93a828.js +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/labextensions/@ipi/notebook-extension/static/style.js +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/labextensions/@ipi/notebook-extension/static/third-party-licenses.json +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/notebook_publisher.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/_model.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/api.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/_agents_md_impl.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/_image_outputs_impl.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/agents_md.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/autoreload.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/dataframe_display.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/http_user_agent.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/image_outputs.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/import_guidance.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/pdb.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/pip_guidance.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/builtins/project_import.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/catalog.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/discovery.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/kernel.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/py.typed +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/plugins/server_deps.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/py.typed +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/records/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/records/py.typed +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/redaction.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/references.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/_subprocess.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/audit.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/bootstrap.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/cell_types.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/concurrent.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/context.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/debugger.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/formatters.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/magics.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/path_context.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/project.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/py.typed +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/replay.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/runtime/state_delta.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/__main__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/builtins/__init__.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/builtins/view_image.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/execution_content.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/plugin_resolver.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/plugin_tools.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/py.typed +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/server/server.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/session.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipi/tunnel.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipinb.egg-info/SOURCES.txt +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipinb.egg-info/dependency_links.txt +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipinb.egg-info/entry_points.txt +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipinb.egg-info/requires.txt +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/src/ipinb.egg-info/top_level.txt +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_ansi.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_config.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_context_runtime.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_credential_boundaries.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_credential_redaction.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_debugger.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_editable_requirements.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_iopub_reducer.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_jupyter_server.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_kernel_address.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_kernel_regressions.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_late_iopub.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_notebook_mirror.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_notebook_mirror_writer.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_notebook_publisher.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_notebook_publisher_e2e.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_output_noise.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_owner_watchdog.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_packaging_namespace.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_platform_support.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_plugin_kernel_integration.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_portable_uv.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_references.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_self_wheel.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_session.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_smoke.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_timing.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_toml.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_transport_staging.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/core/test_tunnel.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/release_smoke.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_bootstrap.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_agents_md.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_autoreload.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_dataframe_display.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_http_user_agent.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_image_outputs.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_import_guidance.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_pdb.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_pip_guidance.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_builtin_project_import.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_context.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_formatters.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_magics.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_model_output.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_path_context.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_plugin_api.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_plugin_catalog.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_plugin_discovery.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_plugin_kernel.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_plugin_server_deps.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_project.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/runtime/test_smoke.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/conftest.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_builtin_view_image.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_main.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_plugin_resolver.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_plugin_tools.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_server.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/server/test_stdio_shutdown.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_cell_export.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_consolidated_tools.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_debugger.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_execution_content_errors.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_namespace.py +0 -0
- {ipinb-0.2.0 → ipinb-0.4.0}/tests/test_package_boundaries.py +0 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Breaking Changes
|
|
2
2
|
|
|
3
|
+
## 2026-10-28: Registry-qualified handles (0.4.0)
|
|
4
|
+
|
|
5
|
+
Public kernel and cell IDs now include a persisted nine-digit decimal registry prefix, for example `123456789k0` and `123456789c1`. Kernel inventory cursors include that prefix too. IDs and cursors belong to their issuing server; pass returned values unchanged. Independent servers no longer issue identical handles by construction, although a random prefix collision remains possible. MCP kernel directories use the qualified kernel ID. Internal numeric execution indices and low-level session helpers are unchanged.
|
|
6
|
+
|
|
7
|
+
**Migration:** Bare `k0`/`c1` handles and old cursors are not supported. Start a fresh IPi server and use its returned IDs. If `server.registry_root` points to a database with retained unqualified IDs, choose a new directory; startup rejects the old registry and preserves its records. Keep that directory with the previous IPi version to inspect historical records. Existing servers retain their current behavior until stopped; live Python state cannot transfer to a replacement server.
|
|
8
|
+
|
|
9
|
+
## 2026-10-27: Private uv kernel environments (0.3.0)
|
|
10
|
+
|
|
11
|
+
Every local and SSH kernel uses an isolated uv environment. Runtime and additional dependencies may override project pins inside that environment. IPi no longer turns every installed project version into a constraint. Project `.venv` and `uv.lock` stay unchanged. Live `%pip` changes remain private to the kernel. Strict `kernel.locked` checks the base project's lock; overlay versions may still differ.
|
|
12
|
+
|
|
13
|
+
The `venv` argument is removed from `create_kernel`, `Kernel.launch`, and transport launch requests, and from returned kernel records. IPi requires uv 0.12.3 or later on the execution host. Existing running servers and kernels retain their old behavior until restarted.
|
|
14
|
+
|
|
15
|
+
**Migration:** Upgrade uv, remove `venv` arguments, and set `cwd` to the intended uv project or scratch directory. Put project requirements in its `pyproject.toml`, and pass kernel-only requirements through `additional_dependencies`. Use project Python selection such as `.python-version`; do not build a separate venv for IPi. Review workflows that assumed kernel imports must use exactly the project's locked versions. New calls to a failed kernel now report `kernel_setup_failed` with the stored cause instead of `kernel_closed`; explicitly closed kernels keep the closed response.
|
|
16
|
+
|
|
3
17
|
## 2026-10-24: No host hook support (0.2.0)
|
|
4
18
|
|
|
5
19
|
IPi 0.2.0 is a plain MCP notebook server. It installs no hooks and receives no host events.
|
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
All notable user-facing changes are recorded here. Detailed API removals and
|
|
4
4
|
migration steps are maintained in [BREAKING_CHANGES.md](BREAKING_CHANGES.md).
|
|
5
5
|
|
|
6
|
+
## 0.4.0
|
|
7
|
+
|
|
8
|
+
- Qualify public kernel and cell handles with a persisted nine-digit decimal registry prefix while retaining compact, never-reused counters. Kernel inventory cursors include the registry prefix too.
|
|
9
|
+
- Explain server ownership in unknown-handle errors and notebook guidance. Cross-agent work goes through the agent that owns the notebook; there is no cross-server routing.
|
|
10
|
+
- Breaking: bare handles and old cursors are no longer supported. Registries with retained unqualified IDs require a new registry directory; existing records are preserved for inspection with the previous version. See [BREAKING_CHANGES.md](BREAKING_CHANGES.md).
|
|
11
|
+
|
|
12
|
+
## 0.3.0
|
|
13
|
+
|
|
14
|
+
- Restore native uv dependency overrides in private per-kernel environments. Runtime dependencies can override project pins without changing project environments or lockfiles; live installs stay private to each kernel.
|
|
15
|
+
- Remove explicit `venv` attachment from kernel APIs and records. Select the project through `cwd` and request extra packages through `additional_dependencies`.
|
|
16
|
+
- Require uv 0.12.3 or later for local and SSH kernels. Keep temporary lock resolution by default and optional strict base-lock validation.
|
|
17
|
+
- Return the original redacted kernel setup error when Python is submitted after startup failed, rather than the generic `kernel_closed` error.
|
|
18
|
+
|
|
6
19
|
## 0.2.0
|
|
7
20
|
|
|
8
21
|
- Breaking: IPi has no host hook support. Start context, the session trace, harness Bash commands as notebook cells, `bash[...]` shell history, the inline-Python nudge, and Claude session identity in kernels are gone (Codex kernels keep `CODEX_THREAD_ID`); the `install`, `install-hooks` and `doctor-narration` commands, the plugin hook API, `ipi.import_path` (use `toolfuncs.load`), the `ipi` command alias and the empty `mcp` extra are removed; IPi requires `toolfuncs>=3,<4`. See [BREAKING_CHANGES.md](BREAKING_CHANGES.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipinb
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Persistent IPython notebooks for MCP agents
|
|
5
5
|
Author-email: Nima Shoghi <nimashoghi@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -104,7 +104,7 @@ Execution requires an explicit `kernel_id`. The default observation window is fi
|
|
|
104
104
|
|
|
105
105
|
Managed kernels keep IPython history in memory because the notebook and registry are the durable execution record. Kernel creation is explicit, apart from optional discoverable startup prewarming. A closed or lost handle never creates a replacement.
|
|
106
106
|
|
|
107
|
-
Handles
|
|
107
|
+
Handles combine a persisted nine-digit decimal registry prefix with `k` or `c` and a durable counter, such as `123456789k0` and `123456789c1`. Pass them unchanged to their originating registry; IDs are never reused within that registry. Tool responses provide one structured JSON payload with typed resource, handle, cell, inventory, or error envelopes. Output cursors belong to each reader. Large sources and events provide immutable MCP resource URIs and byte counts. Use `read_cell(..., include_artifact_metadata=True)` for artifact filesystem paths, SHA-256 checksums, and MIME types.
|
|
108
108
|
|
|
109
109
|
`ipython` returns its bounded cell record plus any images the cell displayed as MCP
|
|
110
110
|
image content, so `plt.show()` is one step instead of a path the model has to
|
|
@@ -117,10 +117,10 @@ Each notebook runtime gets a new session. Local sessions are stored under:
|
|
|
117
117
|
```text
|
|
118
118
|
<initial-cwd>/.agents/sessions/<session-id>/
|
|
119
119
|
session.jsonl
|
|
120
|
-
kernels/
|
|
121
|
-
kernels/
|
|
122
|
-
kernels/
|
|
123
|
-
kernels/
|
|
120
|
+
kernels/123456789k1/notebook.ipynb
|
|
121
|
+
kernels/123456789k1/outputs/manifest.json
|
|
122
|
+
kernels/123456789k1/outputs/c1/g-<sha256-prefix>/input.py
|
|
123
|
+
kernels/123456789k1/outputs/c1/g-<sha256-prefix>/o1-stdout.txt
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
Every input and every retained Jupyter MIME output has a durable local
|
|
@@ -158,7 +158,7 @@ Kernels always write an archival `notebook.ipynb`. Publish a specific live
|
|
|
158
158
|
notebook only when someone needs to open it:
|
|
159
159
|
|
|
160
160
|
```text
|
|
161
|
-
publish(kernel_id=
|
|
161
|
+
publish(kernel_id=kernel_id, cells={cell_id: "Result"})
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
The tool starts one private Notebook 7 child attached to the existing IPi
|
|
@@ -244,7 +244,7 @@ SSH URI:
|
|
|
244
244
|
```python
|
|
245
245
|
create_kernel(cwd="/Users/me/local-project")
|
|
246
246
|
create_kernel(cwd="ssh://gpu-box/opt/projects/model")
|
|
247
|
-
create_kernel(cwd="ssh://alice@gpu-box:2222/opt/projects/model"
|
|
247
|
+
create_kernel(cwd="ssh://alice@gpu-box:2222/opt/projects/model")
|
|
248
248
|
```
|
|
249
249
|
|
|
250
250
|
The URI path is the absolute working directory on the target. Host aliases,
|
|
@@ -333,9 +333,9 @@ Fresh kernels make a small general-purpose module set available: `typing_extensi
|
|
|
333
333
|
|
|
334
334
|
Use `publication.shared_dependencies` for packages that must be installed in both the kernel and the lazily created Notebook 7 environment, such as packages that ship a JupyterLab frontend extension. Shared entries are automatically included in every kernel, so do not duplicate them under `kernel.additional_dependencies`. The publisher uses the exact package versions and sources selected by its kernel. Ordinary kernel-only packages remain in `kernel.additional_dependencies`; installing one live with `%pip` requires no publication change. Put personal scientific and widget defaults in `kernel.scratch_dependencies` and `publication.scratch_shared_dependencies` to keep them out of project kernels.
|
|
335
335
|
|
|
336
|
-
Local and SSH kernels use ephemeral `uv run --isolated` environments. uv selects the project, workspace membership, Python interpreter, sources, and normal default groups. IPi does not enable all extras or groups. Missing or stale locks are resolved temporarily without writing `uv.lock`, and IPi does not create or synchronize `.venv`. Set `kernel.locked = true` to require an existing current lock.
|
|
336
|
+
Local and SSH kernels use ephemeral `uv run --isolated` environments. uv selects the project, workspace membership, Python interpreter, sources, and normal default groups. IPi does not enable all extras or groups. Missing or stale locks are resolved temporarily without writing `uv.lock`, and IPi does not create or synchronize `.venv`. Set `kernel.locked = true` to require an existing current lock. Strict-lock mode checks the base project lock; kernel overrides can still select different package versions.
|
|
337
337
|
|
|
338
|
-
IPi
|
|
338
|
+
IPi requires uv 0.12.3 or later. Its runtime and additional dependencies use native uv overlays and may override project package pins. Each kernel has a private writable environment: live `%pip` changes affect only that kernel. Select the project with `cwd` and request extra packages with `additional_dependencies`; explicit venv attachment is not supported. Approved direnv settings apply to preparation and launch; IPi does not approve an `.envrc`.
|
|
339
339
|
|
|
340
340
|
When `tools.view_image` is omitted, the public tool is disabled on stdio and
|
|
341
341
|
enabled on HTTP, SSE, and streamable HTTP. Set it explicitly to `true` or
|
|
@@ -61,7 +61,7 @@ Execution requires an explicit `kernel_id`. The default observation window is fi
|
|
|
61
61
|
|
|
62
62
|
Managed kernels keep IPython history in memory because the notebook and registry are the durable execution record. Kernel creation is explicit, apart from optional discoverable startup prewarming. A closed or lost handle never creates a replacement.
|
|
63
63
|
|
|
64
|
-
Handles
|
|
64
|
+
Handles combine a persisted nine-digit decimal registry prefix with `k` or `c` and a durable counter, such as `123456789k0` and `123456789c1`. Pass them unchanged to their originating registry; IDs are never reused within that registry. Tool responses provide one structured JSON payload with typed resource, handle, cell, inventory, or error envelopes. Output cursors belong to each reader. Large sources and events provide immutable MCP resource URIs and byte counts. Use `read_cell(..., include_artifact_metadata=True)` for artifact filesystem paths, SHA-256 checksums, and MIME types.
|
|
65
65
|
|
|
66
66
|
`ipython` returns its bounded cell record plus any images the cell displayed as MCP
|
|
67
67
|
image content, so `plt.show()` is one step instead of a path the model has to
|
|
@@ -74,10 +74,10 @@ Each notebook runtime gets a new session. Local sessions are stored under:
|
|
|
74
74
|
```text
|
|
75
75
|
<initial-cwd>/.agents/sessions/<session-id>/
|
|
76
76
|
session.jsonl
|
|
77
|
-
kernels/
|
|
78
|
-
kernels/
|
|
79
|
-
kernels/
|
|
80
|
-
kernels/
|
|
77
|
+
kernels/123456789k1/notebook.ipynb
|
|
78
|
+
kernels/123456789k1/outputs/manifest.json
|
|
79
|
+
kernels/123456789k1/outputs/c1/g-<sha256-prefix>/input.py
|
|
80
|
+
kernels/123456789k1/outputs/c1/g-<sha256-prefix>/o1-stdout.txt
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
Every input and every retained Jupyter MIME output has a durable local
|
|
@@ -115,7 +115,7 @@ Kernels always write an archival `notebook.ipynb`. Publish a specific live
|
|
|
115
115
|
notebook only when someone needs to open it:
|
|
116
116
|
|
|
117
117
|
```text
|
|
118
|
-
publish(kernel_id=
|
|
118
|
+
publish(kernel_id=kernel_id, cells={cell_id: "Result"})
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
The tool starts one private Notebook 7 child attached to the existing IPi
|
|
@@ -201,7 +201,7 @@ SSH URI:
|
|
|
201
201
|
```python
|
|
202
202
|
create_kernel(cwd="/Users/me/local-project")
|
|
203
203
|
create_kernel(cwd="ssh://gpu-box/opt/projects/model")
|
|
204
|
-
create_kernel(cwd="ssh://alice@gpu-box:2222/opt/projects/model"
|
|
204
|
+
create_kernel(cwd="ssh://alice@gpu-box:2222/opt/projects/model")
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
The URI path is the absolute working directory on the target. Host aliases,
|
|
@@ -290,9 +290,9 @@ Fresh kernels make a small general-purpose module set available: `typing_extensi
|
|
|
290
290
|
|
|
291
291
|
Use `publication.shared_dependencies` for packages that must be installed in both the kernel and the lazily created Notebook 7 environment, such as packages that ship a JupyterLab frontend extension. Shared entries are automatically included in every kernel, so do not duplicate them under `kernel.additional_dependencies`. The publisher uses the exact package versions and sources selected by its kernel. Ordinary kernel-only packages remain in `kernel.additional_dependencies`; installing one live with `%pip` requires no publication change. Put personal scientific and widget defaults in `kernel.scratch_dependencies` and `publication.scratch_shared_dependencies` to keep them out of project kernels.
|
|
292
292
|
|
|
293
|
-
Local and SSH kernels use ephemeral `uv run --isolated` environments. uv selects the project, workspace membership, Python interpreter, sources, and normal default groups. IPi does not enable all extras or groups. Missing or stale locks are resolved temporarily without writing `uv.lock`, and IPi does not create or synchronize `.venv`. Set `kernel.locked = true` to require an existing current lock.
|
|
293
|
+
Local and SSH kernels use ephemeral `uv run --isolated` environments. uv selects the project, workspace membership, Python interpreter, sources, and normal default groups. IPi does not enable all extras or groups. Missing or stale locks are resolved temporarily without writing `uv.lock`, and IPi does not create or synchronize `.venv`. Set `kernel.locked = true` to require an existing current lock. Strict-lock mode checks the base project lock; kernel overrides can still select different package versions.
|
|
294
294
|
|
|
295
|
-
IPi
|
|
295
|
+
IPi requires uv 0.12.3 or later. Its runtime and additional dependencies use native uv overlays and may override project package pins. Each kernel has a private writable environment: live `%pip` changes affect only that kernel. Select the project with `cwd` and request extra packages with `additional_dependencies`; explicit venv attachment is not supported. Approved direnv settings apply to preparation and launch; IPi does not approve an `.envrc`.
|
|
296
296
|
|
|
297
297
|
When `tools.view_image` is omitted, the public tool is disabled on stdio and
|
|
298
298
|
enabled on HTTP, SSE, and streamable HTTP. Set it explicitly to `true` or
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
IPi is a notebook runtime exposed through MCP. Codex or Claude Code owns the agent loop; IPi owns persistent IPython kernels, execution records, notebooks, and artifacts. IPi installs and receives no host hooks.
|
|
4
4
|
|
|
5
|
+
## Kernel environment ownership
|
|
6
|
+
|
|
7
|
+
Local and SSH kernels require uv 0.12.3 or later and use one `uv run --isolated` path. uv discovers the project/workspace, Python, local sources, and default groups. Runtime and task requirements use native overlays that can override project pins. IPi does not freeze the base package inventory, attach existing venvs, synchronize `.venv`, or write `uv.lock`. Missing or stale locks resolve temporarily unless `kernel.locked` requires a current base lock. Each launch has a private writable environment, including when uv can skip an already-satisfied overlay. Live package changes belong to that kernel.
|
|
8
|
+
|
|
9
|
+
Kernel setup remains asynchronous. Work accepted during setup receives its retained setup failure if provisioning fails. New Python submissions after failure return the same redacted cause, with the kernel ID. Replaying an accepted request ID still recovers the original cell.
|
|
10
|
+
|
|
5
11
|
## Distribution Boundary
|
|
6
12
|
|
|
7
13
|
Installed archive plugins accept content hashes from PEP 610 `archive_info` or the URL hash fragment retained by uv for local wheels. Both forms produce the same source identity. Conflicting hashes, malformed fragments, and archives with no content hash remain errors.
|
|
@@ -115,7 +121,7 @@ Bash tool registration is process-wide and disabled by default. Set `IPI_MCP_ENA
|
|
|
115
121
|
|
|
116
122
|
`ipython(kernel_id, code, yield_time_ms, request_id)` accepts work and optionally observes it. A zero observation window always returns a `handle`, including for a fast completed execution. Positive observations return a `cell` view with truthful queued, running, paused, succeeded, failed, interrupted, or lost state. Live debugger stops use `paused`; unhandled failures finish as `failed` while optionally retaining postmortem frames. An interruption request is independent of execution state.
|
|
117
123
|
|
|
118
|
-
`read_cell(cell_id, yield_time_ms=0)` reads immediately by default and can wait up to 30 seconds for Python output or completion. Python replies omit source, origin, created_at, and request_id; Markdown remains immediate and includes its source and metadata. These fields remain stored internally, and Python source is available through `ipi://cells/{cell_id}/source`. It uses caller-owned output cursors such as `
|
|
124
|
+
`read_cell(cell_id, yield_time_ms=0)` reads immediately by default and can wait up to 30 seconds for Python output or completion. Python replies omit source, origin, created_at, and request_id; Markdown remains immediate and includes its source and metadata. These fields remain stored internally, and Python source is available through `ipi://cells/{cell_id}/source`. It uses caller-owned output cursors such as `123456789c1:17`. Kernel inventories use `<registry-prefix>k:<offset>` and cell inventories use `<kernel_id>:<offset>`; the identity binds each cursor to its resource and page type. Callers pass cursors unchanged. Terminal execution does not imply that the current page exhausts output. Repeated reads replay the same retained events; a later event increments the revision without reopening terminal execution. IOPub events are sequenced and persisted before response construction. Terminal completion waits for both the shell result and ordered idle message.
|
|
119
125
|
|
|
120
126
|
Model-facing output pages contain ordered `blocks`. Adjacent stream events from the same stream are concatenated into a stdout or stderr text block without changing the retained log. Other events preserve their identity and content, including immutable artifact references. The page cursor records the next underlying event, not the next block. Byte limits are applied after this projection; joining never crosses a different stream or a non-stream event.
|
|
121
127
|
|
|
@@ -139,7 +145,7 @@ The notebook mirrors retained records without re-executing them. Cross-cell disp
|
|
|
139
145
|
|
|
140
146
|
`markdown` appends prose with optional retry deduplication and returns only `{"kind":"markdown","cell_id":"..."}`. An identical retry returns the same receipt. Use `read_cell(cell_id)` to retrieve the retained prose and metadata. `publish(kernel_id, cells={cell_id: caption})` optionally highlights terminal Python cells in the full notebook without adding executions or rows. Selection is validated before changing presentation: every selected cell must be accessible, terminal, and belong to the named kernel. Omitted cells keep their existing highlights. Publication reconciles retained records before exposing the live sidecar; a notebook synchronization failure cannot silently become a successful stale publication. Archival records survive live-kernel close under the configured retention policy, which has no automatic record expiry by default.
|
|
141
147
|
|
|
142
|
-
Kernel handles
|
|
148
|
+
Kernel handles combine a persisted nine-digit decimal registry prefix with an unpadded, zero-based counter (`123456789k0`, `123456789k1`, ...); cell handles use the same prefix and a one-based counter (`123456789c1`, `123456789c2`, ...). Each registry draws its prefix once, uniformly from 100000000 through 999999999, and stores it in SQLite metadata. Reopening the database preserves the prefix. Python, Bash, markdown, and browser executions share the cell counter across kernels, so a cell ID alone resolves its record. Allocation state lives in the same SQLite database as retained resources and is committed before acceptance, so closed or expired records, failed acceptance, and owner restarts cannot recycle handles. Registries with retained unqualified IDs are rejected at startup without discarding their records; use a fresh registry root after upgrading. Foreign handles fail local lookup unless two registries draw the same prefix. This is probabilistic separation: a particular independent pair collides with probability 1/900000000, independent of retained cell count. Prefix collisions across many registries follow the birthday bound, and matching counters can then alias. Prefixes are not authentication secrets. There is no cross-server routing; ask the owning agent to run follow-up work and return results. The prefix adds three tokens per ID under the measured o200k_base and cl100k_base encodings; counters keep growing without padding or wrapping. Execution replies contain one structured JSON payload, with an explicitly empty text-content list. Image blocks use MCP content while their complete MIME events remain retrievable as artifacts, avoiding a base64 copy in JSON.
|
|
143
149
|
|
|
144
150
|
## Plugin Lifecycle
|
|
145
151
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
IPi exposes one optional-use debugger tool backed by IPython's Pdb engine:
|
|
4
4
|
|
|
5
5
|
```python
|
|
6
|
-
ipdb(kernel_id=
|
|
7
|
-
ipdb(kernel_id=
|
|
6
|
+
ipdb(kernel_id=kernel_id, cell_id=cell_id, command="where")
|
|
7
|
+
ipdb(kernel_id=kernel_id, command="break /absolute/path/model.py:42")
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
Every call names a kernel. Add a cell ID for frame inspection, Python evaluation, or execution control. Omit the cell ID for kernel-wide breakpoint configuration and exception-stop policy. There is no active-target selector.
|
|
@@ -19,7 +19,7 @@ Use `where`, `up`, `down`, `args`, `p expression`, `pp expression`, `list`, or `
|
|
|
19
19
|
|
|
20
20
|
Insert `breakpoint()` in a submitted cell or set a source breakpoint before running it. The cell reports `paused` and a source location. `step`, `next`, `return`, `until`, and `continue` use the real debugger engine. `quit` abandons that execution and unwinds its cleanup. Breakpoint configuration uses Pdb syntax, including `break`, `tbreak`, `condition`, `ignore`, `enable`, `disable`, and `clear`. Bare `clear` clears all breakpoints without prompting. Kernel-scoped source breakpoints should name a file and line; frame-relative expressions require a cell target.
|
|
21
21
|
|
|
22
|
-
`ipdb(kernel_id=
|
|
22
|
+
`ipdb(kernel_id=kernel_id, command="exceptions raised")` stops when an exception is raised, before handling; this includes exceptions that user code may catch. `exceptions off` restores default postmortem-only behavior. Internal iteration termination is excluded from automatic raised-exception stops.
|
|
23
23
|
|
|
24
24
|
A live pause occupies its subshell. Other subshells and debugger commands remain usable. A pause also stops other tasks on that subshell's event loop; shared locks and mutable objects retain their normal Python behavior. There is no process-wide freeze or ability to step inside native C/CUDA operations. Interrupts and abandonment can be delayed by blocking native code or user code that suppresses cancellation.
|
|
25
25
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Execution, results, and recovery
|
|
2
2
|
|
|
3
|
-
Read this when work runs longer than one tool call, output is large, or a connection drops. For overlapping submissions, also read [Parallel execution](parallel-execution.md). Examples below are MCP tool calls;
|
|
3
|
+
Read this when work runs longer than one tool call, output is large, or a connection drops. For overlapping submissions, also read [Parallel execution](parallel-execution.md). Examples below are MCP tool calls; `kernel_id` and `cell_id` stand for exact handles returned by this server.
|
|
4
4
|
|
|
5
5
|
## Submit and observe
|
|
6
6
|
|
|
7
7
|
```python
|
|
8
|
-
ipython(kernel_id=
|
|
9
|
-
read_cell(cell_id=
|
|
8
|
+
ipython(kernel_id=kernel_id, code="result = expensive_calculation()", yield_time_ms=0, request_id="calculate-1")
|
|
9
|
+
read_cell(cell_id=cell_id, yield_time_ms=10000)
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
A `handle` means accepted, not completed. `yield_time_ms` limits how long the caller observes; it does not limit execution. A cancelled or disconnected observer leaves accepted work owned by IPi. Keep the kernel and cell IDs, then observe that same cell rather than resubmitting its code.
|
|
@@ -25,10 +25,10 @@ Large source or output bodies supply immutable MCP resource URIs. Read the retur
|
|
|
25
25
|
|
|
26
26
|
Supply `request_id` when creating a kernel, submitting Python or Markdown, or issuing a debugger command if a lost response would make repetition risky. Reuse that key with the same operation and payload to recover its accepted record. Reusing a key for a different payload is rejected. A fresh key requests fresh work and can repeat side effects. Optional Bash also supports request IDs when enabled.
|
|
27
27
|
|
|
28
|
-
HTTP and stdio expose the same execution API. HTTP reconnection does not require a new kernel: retain the kernel ID and use `list_cells(kernel_id=...)` when cell records need recovery. Closed or lost kernels do not contain usable live Python state. Identifiers do not replace authentication.
|
|
28
|
+
HTTP and stdio expose the same execution API. HTTP reconnection to the same server does not require a new kernel: retain the kernel ID and use `list_cells(kernel_id=...)` when cell records need recovery. Closed or lost kernels do not contain usable live Python state. Kernel and cell IDs belong to the IPi server that issued them; pass them unchanged. For another agent's notebook, ask that agent to run follow-up work and return results. Identifiers do not replace authentication.
|
|
29
29
|
|
|
30
30
|
## Cancellation and debugger state
|
|
31
31
|
|
|
32
|
-
`interrupt(cell_id=
|
|
32
|
+
`interrupt(cell_id=cell_id)` requests cancellation of that execution only. Continue observing its outcome. Native blocking code, suppressed cancellation, and descendant activity can outlive the request. `close_kernel(kernel_id=kernel_id)` discards the named kernel's live state; retained records remain available under the storage policy. Finishing an answer is not a reason to close a reusable kernel.
|
|
33
33
|
|
|
34
34
|
A new ordinary submission to a kernel abandons existing live debugger pauses and discards existing postmortem inspection before admission. Recovering an existing execution retry key does not repeat that cleanup. See [Debugging](debugging.md) before choosing to resume or move on.
|
|
@@ -4,17 +4,17 @@ Read this when choosing a working directory, Python environment, dependency over
|
|
|
4
4
|
|
|
5
5
|
## Choose the execution environment
|
|
6
6
|
|
|
7
|
-
Reuse a suitable kernel ID
|
|
7
|
+
Reuse a suitable kernel ID returned by this IPi server. When creating a kernel, pass an existing absolute working directory:
|
|
8
8
|
|
|
9
9
|
```python
|
|
10
10
|
create_kernel(cwd="/absolute/project", additional_dependencies=["numpy", "pandas"], request_id="analysis-kernel")
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The result may report `starting`. Python submitted with its returned `kernel_id` waits for setup.
|
|
13
|
+
The result may report `starting`. Python submitted with its returned `kernel_id` waits for setup. Submit work with the returned ID and observe its cell; setup failures are returned directly even if setup failed before submission. Configuration and plugins resolve for that kernel's cwd; a kernel created for another project can have a different environment.
|
|
14
14
|
|
|
15
15
|
IPi uses ephemeral `uv run --isolated` environments. uv selects the project or workspace member for `cwd`, its Python version, sources, and normal default dependency groups. IPi does not create or synchronize `.venv`. It resolves missing or stale locks temporarily without writing `uv.lock`; set `kernel.locked = true` in IPi configuration when a current lock is required. Approved direnv settings apply before resolution. IPi does not approve an `.envrc`.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
IPi requires uv 0.12.3 or later. Initial startup includes a 180-second dependency preparation allowance in addition to the Jupyter readiness budget; `IPI_UV_BASE_ENVIRONMENT_TIMEOUT_S` changes that allowance for local and SSH launches. Select a project with `cwd` and use `additional_dependencies` for task requirements; explicit venv attachment is not supported. Native uv overlays let runtime and added packages override project pins inside the disposable kernel environment. Strict-lock mode checks the base lock, not the overlay versions. Personal defaults in `kernel.scratch_dependencies` and `publication.scratch_shared_dependencies` apply only outside a uv project. Live `%pip` changes are private to this kernel and do not change other kernels or later launches. The environment hint describes available modules and distribution/import aliases. Query the actual interpreter when needed:
|
|
18
18
|
|
|
19
19
|
```python
|
|
20
20
|
import sys
|
|
@@ -42,7 +42,7 @@ Python imports, file access, and Bash commands run on the target. Do not substit
|
|
|
42
42
|
The `bash` tool is disabled by default. Set `IPI_MCP_ENABLE_BASH_TOOL=1` before server startup to advertise it. When present:
|
|
43
43
|
|
|
44
44
|
```python
|
|
45
|
-
bash(kernel_id=
|
|
45
|
+
bash(kernel_id=kernel_id, cmd="pwd", yield_time_ms=0, request_id="inspect-directory")
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Bash runs in the selected kernel environment and follows Python's cell handles, observation, retries, and targeted cancellation. Read its retained output with `read_cell`. Like a new `ipython` submission, it moves on from existing debugger pauses in that kernel. For calculations that should reuse Python variables, imports, or live objects, use `ipython`.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Contract
|
|
6
6
|
|
|
7
|
-
- Use `publish(kernel_id=
|
|
7
|
+
- Use `publish(kernel_id=kernel_id, cells={cell_id: "Main result"})`. The optional mapping highlights terminal Python cells in the full live notebook. It never filters or reruns notebook content. All selected cells must belong to the named kernel.
|
|
8
8
|
- Null captions highlight without text. Omitted cells retain their existing highlights; omit the map to publish without changing presentation. Empty notebooks can be published.
|
|
9
9
|
- The complete mapping is validated before presentation changes. Valid highlights are retained even if endpoint creation subsequently fails.
|
|
10
10
|
- A successful call returns the complete
|
|
@@ -9,8 +9,8 @@ Finish shared setup first: imports, function definitions, and any data both oper
|
|
|
9
9
|
For example, suppose a completed setup cell defined `load_metadata()` and `summarize_metrics()`, and neither operation depends on or mutates the other's state. These are MCP tool calls, not Python to execute inside the kernel:
|
|
10
10
|
|
|
11
11
|
```python
|
|
12
|
-
ipython(kernel_id=
|
|
13
|
-
ipython(kernel_id=
|
|
12
|
+
ipython(kernel_id=kernel_id, code="metadata = load_metadata()", yield_time_ms=0)
|
|
13
|
+
ipython(kernel_id=kernel_id, code="metrics = summarize_metrics()", yield_time_ms=0)
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
Use each returned cell ID to observe that operation:
|
|
@@ -22,13 +22,13 @@ figure.savefig("result.png", dpi=200, bbox_inches="tight")
|
|
|
22
22
|
display(figure)
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Use the optional `view_image(kernel_id=
|
|
25
|
+
Use the optional `view_image(kernel_id=kernel_id, path="result.png")` tool to inspect an existing PNG, JPEG, GIF, or WebP on the kernel's filesystem. Relative paths resolve under that kernel's cwd, including for SSH kernels. This reads an image; it does not execute a cell. If that tool is absent from the catalog, inspect through an available image-capable host surface or an appropriate IPython display.
|
|
26
26
|
|
|
27
27
|
## Add prose and highlight results
|
|
28
28
|
|
|
29
29
|
```python
|
|
30
|
-
markdown(kernel_id=
|
|
31
|
-
publish(kernel_id=
|
|
30
|
+
markdown(kernel_id=kernel_id, source="## Result\nThe experiment completed with the parameters below.")
|
|
31
|
+
publish(kernel_id=kernel_id, cells={cell_id: "Main result", validation_cell_id: "Validation"})
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
These are MCP calls. Markdown appends a notebook cell, including while Python runs. Publication highlights selected terminal Python cells in the full live notebook; it does not select a subset for export or rerun the code. Captions describe already-retained results. See [Notebook publishing](notebook-publishing.md) for URL lifetime and highlight updates.
|
|
@@ -3,7 +3,9 @@ name: notebook
|
|
|
3
3
|
description: Use persistent Python kernels for multi-step investigation, analysis, prototyping, and verification with reusable state and rich output.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Reuse a suitable kernel ID
|
|
6
|
+
Reuse a suitable kernel ID returned by this IPi server, or create a kernel for the required cwd and environment. Retain its `kernel_id` and pass it to submissions and notebook mutations. A starting kernel queues Python until setup completes.
|
|
7
|
+
|
|
8
|
+
Kernel and cell IDs belong to the IPi server that issued them; pass them unchanged. For another agent's notebook, ask that agent to run follow-up work and return results.
|
|
7
9
|
|
|
8
10
|
Use IPi's native parallel execution for independent work: submit separate cells to the same kernel with `yield_time_ms=0` before waiting on their results. IPi schedules them in bounded subshells that share Python globals; no manual subshell setup is needed. Use distinct names or synchronization, and wait for prerequisite cells to succeed before submitting dependent code. Create another kernel when work needs isolated globals or incompatible process state. See [Parallel execution](references/parallel-execution.md) for submission patterns, shared-state constraints, and capacity handling.
|
|
9
11
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
IPi exposes one optional-use debugger tool backed by IPython's Pdb engine:
|
|
4
4
|
|
|
5
5
|
```python
|
|
6
|
-
ipdb(kernel_id=
|
|
7
|
-
ipdb(kernel_id=
|
|
6
|
+
ipdb(kernel_id=kernel_id, cell_id=cell_id, command="where")
|
|
7
|
+
ipdb(kernel_id=kernel_id, command="break /absolute/path/model.py:42")
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
Every call names a kernel. Add a cell ID for frame inspection, Python evaluation, or execution control. Omit the cell ID for kernel-wide breakpoint configuration and exception-stop policy. There is no active-target selector.
|
|
@@ -19,7 +19,7 @@ Use `where`, `up`, `down`, `args`, `p expression`, `pp expression`, `list`, or `
|
|
|
19
19
|
|
|
20
20
|
Insert `breakpoint()` in a submitted cell or set a source breakpoint before running it. The cell reports `paused` and a source location. `step`, `next`, `return`, `until`, and `continue` use the real debugger engine. `quit` abandons that execution and unwinds its cleanup. Breakpoint configuration uses Pdb syntax, including `break`, `tbreak`, `condition`, `ignore`, `enable`, `disable`, and `clear`. Bare `clear` clears all breakpoints without prompting. Kernel-scoped source breakpoints should name a file and line; frame-relative expressions require a cell target.
|
|
21
21
|
|
|
22
|
-
`ipdb(kernel_id=
|
|
22
|
+
`ipdb(kernel_id=kernel_id, command="exceptions raised")` stops when an exception is raised, before handling; this includes exceptions that user code may catch. `exceptions off` restores default postmortem-only behavior. Internal iteration termination is excluded from automatic raised-exception stops.
|
|
23
23
|
|
|
24
24
|
A live pause occupies its subshell. Other subshells and debugger commands remain usable. A pause also stops other tasks on that subshell's event loop; shared locks and mutable objects retain their normal Python behavior. There is no process-wide freeze or ability to step inside native C/CUDA operations. Interrupts and abandonment can be delayed by blocking native code or user code that suppresses cancellation.
|
|
25
25
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Execution, results, and recovery
|
|
2
2
|
|
|
3
|
-
Read this when work runs longer than one tool call, output is large, or a connection drops. For overlapping submissions, also read [Parallel execution](parallel-execution.md). Examples below are MCP tool calls;
|
|
3
|
+
Read this when work runs longer than one tool call, output is large, or a connection drops. For overlapping submissions, also read [Parallel execution](parallel-execution.md). Examples below are MCP tool calls; `kernel_id` and `cell_id` stand for exact handles returned by this server.
|
|
4
4
|
|
|
5
5
|
## Submit and observe
|
|
6
6
|
|
|
7
7
|
```python
|
|
8
|
-
ipython(kernel_id=
|
|
9
|
-
read_cell(cell_id=
|
|
8
|
+
ipython(kernel_id=kernel_id, code="result = expensive_calculation()", yield_time_ms=0, request_id="calculate-1")
|
|
9
|
+
read_cell(cell_id=cell_id, yield_time_ms=10000)
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
A `handle` means accepted, not completed. `yield_time_ms` limits how long the caller observes; it does not limit execution. A cancelled or disconnected observer leaves accepted work owned by IPi. Keep the kernel and cell IDs, then observe that same cell rather than resubmitting its code.
|
|
@@ -25,10 +25,10 @@ Large source or output bodies supply immutable MCP resource URIs. Read the retur
|
|
|
25
25
|
|
|
26
26
|
Supply `request_id` when creating a kernel, submitting Python or Markdown, or issuing a debugger command if a lost response would make repetition risky. Reuse that key with the same operation and payload to recover its accepted record. Reusing a key for a different payload is rejected. A fresh key requests fresh work and can repeat side effects. Optional Bash also supports request IDs when enabled.
|
|
27
27
|
|
|
28
|
-
HTTP and stdio expose the same execution API. HTTP reconnection does not require a new kernel: retain the kernel ID and use `list_cells(kernel_id=...)` when cell records need recovery. Closed or lost kernels do not contain usable live Python state. Identifiers do not replace authentication.
|
|
28
|
+
HTTP and stdio expose the same execution API. HTTP reconnection to the same server does not require a new kernel: retain the kernel ID and use `list_cells(kernel_id=...)` when cell records need recovery. Closed or lost kernels do not contain usable live Python state. Kernel and cell IDs belong to the IPi server that issued them; pass them unchanged. For another agent's notebook, ask that agent to run follow-up work and return results. Identifiers do not replace authentication.
|
|
29
29
|
|
|
30
30
|
## Cancellation and debugger state
|
|
31
31
|
|
|
32
|
-
`interrupt(cell_id=
|
|
32
|
+
`interrupt(cell_id=cell_id)` requests cancellation of that execution only. Continue observing its outcome. Native blocking code, suppressed cancellation, and descendant activity can outlive the request. `close_kernel(kernel_id=kernel_id)` discards the named kernel's live state; retained records remain available under the storage policy. Finishing an answer is not a reason to close a reusable kernel.
|
|
33
33
|
|
|
34
34
|
A new ordinary submission to a kernel abandons existing live debugger pauses and discards existing postmortem inspection before admission. Recovering an existing execution retry key does not repeat that cleanup. See [Debugging](debugging.md) before choosing to resume or move on.
|
|
@@ -4,17 +4,17 @@ Read this when choosing a working directory, Python environment, dependency over
|
|
|
4
4
|
|
|
5
5
|
## Choose the execution environment
|
|
6
6
|
|
|
7
|
-
Reuse a suitable kernel ID
|
|
7
|
+
Reuse a suitable kernel ID returned by this IPi server. When creating a kernel, pass an existing absolute working directory:
|
|
8
8
|
|
|
9
9
|
```python
|
|
10
10
|
create_kernel(cwd="/absolute/project", additional_dependencies=["numpy", "pandas"], request_id="analysis-kernel")
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The result may report `starting`. Python submitted with its returned `kernel_id` waits for setup.
|
|
13
|
+
The result may report `starting`. Python submitted with its returned `kernel_id` waits for setup. Submit work with the returned ID and observe its cell; setup failures are returned directly even if setup failed before submission. Configuration and plugins resolve for that kernel's cwd; a kernel created for another project can have a different environment.
|
|
14
14
|
|
|
15
15
|
IPi uses ephemeral `uv run --isolated` environments. uv selects the project or workspace member for `cwd`, its Python version, sources, and normal default dependency groups. IPi does not create or synchronize `.venv`. It resolves missing or stale locks temporarily without writing `uv.lock`; set `kernel.locked = true` in IPi configuration when a current lock is required. Approved direnv settings apply before resolution. IPi does not approve an `.envrc`.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
IPi requires uv 0.12.3 or later. Initial startup includes a 180-second dependency preparation allowance in addition to the Jupyter readiness budget; `IPI_UV_BASE_ENVIRONMENT_TIMEOUT_S` changes that allowance for local and SSH launches. Select a project with `cwd` and use `additional_dependencies` for task requirements; explicit venv attachment is not supported. Native uv overlays let runtime and added packages override project pins inside the disposable kernel environment. Strict-lock mode checks the base lock, not the overlay versions. Personal defaults in `kernel.scratch_dependencies` and `publication.scratch_shared_dependencies` apply only outside a uv project. Live `%pip` changes are private to this kernel and do not change other kernels or later launches. The environment hint describes available modules and distribution/import aliases. Query the actual interpreter when needed:
|
|
18
18
|
|
|
19
19
|
```python
|
|
20
20
|
import sys
|
|
@@ -42,7 +42,7 @@ Python imports, file access, and Bash commands run on the target. Do not substit
|
|
|
42
42
|
The `bash` tool is disabled by default. Set `IPI_MCP_ENABLE_BASH_TOOL=1` before server startup to advertise it. When present:
|
|
43
43
|
|
|
44
44
|
```python
|
|
45
|
-
bash(kernel_id=
|
|
45
|
+
bash(kernel_id=kernel_id, cmd="pwd", yield_time_ms=0, request_id="inspect-directory")
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Bash runs in the selected kernel environment and follows Python's cell handles, observation, retries, and targeted cancellation. Read its retained output with `read_cell`. Like a new `ipython` submission, it moves on from existing debugger pauses in that kernel. For calculations that should reuse Python variables, imports, or live objects, use `ipython`.
|
{ipinb-0.2.0/src/ipi/resources → ipinb-0.4.0/ipi/skills/notebook}/references/notebook-publishing.md
RENAMED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Contract
|
|
6
6
|
|
|
7
|
-
- Use `publish(kernel_id=
|
|
7
|
+
- Use `publish(kernel_id=kernel_id, cells={cell_id: "Main result"})`. The optional mapping highlights terminal Python cells in the full live notebook. It never filters or reruns notebook content. All selected cells must belong to the named kernel.
|
|
8
8
|
- Null captions highlight without text. Omitted cells retain their existing highlights; omit the map to publish without changing presentation. Empty notebooks can be published.
|
|
9
9
|
- The complete mapping is validated before presentation changes. Valid highlights are retained even if endpoint creation subsequently fails.
|
|
10
10
|
- A successful call returns the complete
|
{ipinb-0.2.0/src/ipi/resources → ipinb-0.4.0/ipi/skills/notebook}/references/parallel-execution.md
RENAMED
|
@@ -9,8 +9,8 @@ Finish shared setup first: imports, function definitions, and any data both oper
|
|
|
9
9
|
For example, suppose a completed setup cell defined `load_metadata()` and `summarize_metrics()`, and neither operation depends on or mutates the other's state. These are MCP tool calls, not Python to execute inside the kernel:
|
|
10
10
|
|
|
11
11
|
```python
|
|
12
|
-
ipython(kernel_id=
|
|
13
|
-
ipython(kernel_id=
|
|
12
|
+
ipython(kernel_id=kernel_id, code="metadata = load_metadata()", yield_time_ms=0)
|
|
13
|
+
ipython(kernel_id=kernel_id, code="metrics = summarize_metrics()", yield_time_ms=0)
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
Use each returned cell ID to observe that operation:
|
|
@@ -22,13 +22,13 @@ figure.savefig("result.png", dpi=200, bbox_inches="tight")
|
|
|
22
22
|
display(figure)
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Use the optional `view_image(kernel_id=
|
|
25
|
+
Use the optional `view_image(kernel_id=kernel_id, path="result.png")` tool to inspect an existing PNG, JPEG, GIF, or WebP on the kernel's filesystem. Relative paths resolve under that kernel's cwd, including for SSH kernels. This reads an image; it does not execute a cell. If that tool is absent from the catalog, inspect through an available image-capable host surface or an appropriate IPython display.
|
|
26
26
|
|
|
27
27
|
## Add prose and highlight results
|
|
28
28
|
|
|
29
29
|
```python
|
|
30
|
-
markdown(kernel_id=
|
|
31
|
-
publish(kernel_id=
|
|
30
|
+
markdown(kernel_id=kernel_id, source="## Result\nThe experiment completed with the parameters below.")
|
|
31
|
+
publish(kernel_id=kernel_id, cells={cell_id: "Main result", validation_cell_id: "Validation"})
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
These are MCP calls. Markdown appends a notebook cell, including while Python runs. Publication highlights selected terminal Python cells in the full live notebook; it does not select a subset for export or rerun the code. Captions describe already-retained results. See [Notebook publishing](notebook-publishing.md) for URL lifetime and highlight updates.
|
|
@@ -3,6 +3,6 @@ name: notebook-http
|
|
|
3
3
|
description: Use IPi's explicit persistent kernels across reconnecting HTTP MCP clients.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
HTTP and stdio expose the same IPi tools and resource IDs. Follow the notebook skill. Retain `kernel_id` for submissions and notebook mutations, and `cell_id` for observation and interruption. HTTP transport sessions do not own Python state; reconnecting does not require a new kernel. Resource IDs identify records and do not replace authentication.
|
|
6
|
+
HTTP and stdio expose the same IPi tools and resource IDs. Follow the notebook skill. Retain `kernel_id` for submissions and notebook mutations, and `cell_id` for observation and interruption. HTTP transport sessions do not own Python state; reconnecting to the same server does not require a new kernel. IDs from another server are not portable; ask the owning agent to return results. Resource IDs identify records and do not replace authentication.
|
|
7
7
|
|
|
8
8
|
There is no separate logical `session_id`, active-kernel selector, or whole-service kill tool. `close_kernel` ends only its named kernel. Published notebooks remain live until that kernel or the owning IPi process ends; retained records survive under the advertised storage policy.
|
|
@@ -25,6 +25,7 @@ from typing import Any, cast
|
|
|
25
25
|
from jupyter_client import KernelManager
|
|
26
26
|
|
|
27
27
|
from ipi._exception_groups import BaseExceptionGroup
|
|
28
|
+
from ipi._uv_environment import preparation_timeout_s
|
|
28
29
|
from ipi.redaction import redact_exception_message, redact_url_secrets, redact_url_userinfo
|
|
29
30
|
|
|
30
31
|
from .address import SshKernelLocation
|
|
@@ -587,7 +588,6 @@ class SshPreparedTransport:
|
|
|
587
588
|
response = supervisor.request(
|
|
588
589
|
"launch",
|
|
589
590
|
cwd=request.cwd.as_posix(),
|
|
590
|
-
venv=(request.venv.as_posix() if request.venv is not None else None),
|
|
591
591
|
locked=request.locked,
|
|
592
592
|
requirements=list(request.requirements),
|
|
593
593
|
environment=dict(request.environment),
|
|
@@ -1487,14 +1487,13 @@ class _SupervisorClient:
|
|
|
1487
1487
|
with self._request_lock:
|
|
1488
1488
|
if self._closed:
|
|
1489
1489
|
raise SshTransportError("SSH supervisor control channel is closed")
|
|
1490
|
+
timeout = _SUPERVISOR_RESPONSE_SECONDS
|
|
1491
|
+
if operation == "launch":
|
|
1492
|
+
preparation_timeout = preparation_timeout_s()
|
|
1493
|
+
fields["preparation_timeout_s"] = preparation_timeout
|
|
1494
|
+
timeout = _SUPERVISOR_LAUNCH_RESPONSE_SECONDS + preparation_timeout
|
|
1490
1495
|
request_id = self._write_request(operation, fields=fields, one_way=False)
|
|
1491
|
-
response = self._read_message(
|
|
1492
|
-
timeout_s=(
|
|
1493
|
-
_SUPERVISOR_LAUNCH_RESPONSE_SECONDS
|
|
1494
|
-
if operation == "launch"
|
|
1495
|
-
else _SUPERVISOR_RESPONSE_SECONDS
|
|
1496
|
-
)
|
|
1497
|
-
)
|
|
1496
|
+
response = self._read_message(timeout_s=timeout)
|
|
1498
1497
|
if response.get("id") != request_id or response.get("version") != _PROTOCOL_VERSION:
|
|
1499
1498
|
raise SshTransportError("SSH supervisor returned a mismatched control response")
|
|
1500
1499
|
if response.get("ok") is not True:
|