Repository navigation
Run the emitter host from an installed microcosm-emitter command - #21
Merged
Merged
Conversation
`uv tool install microcosm-emitter` now installs a `microcosm-emitter` command. A build starts `microcosm-emitter host` as its own child process, so the host inherits the build's environment variables and user and finds the same Hugging Face credential. - The host reads its parent's creation time itself when no launcher passes it, and refuses to start if the named process is not its parent. - A `hello` request returns the emitter version, the socket protocol versions it accepts and the modules it loaded. - `--skip-unavailable-modules` starts without requested modules this emitter does not install. - `python -m microcosm_emitter.host` keeps working for existing launchers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`load_module` raises `ModuleNotInstalledError` ("No installed module is
named ...") when no entry point provides the module, so the host can skip
it with `--skip-unavailable-modules`. The test still expected the
duplicate-module message for that case and failed in CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without `--parent-created-at`, the host checked `os.getppid()` and only then read the named process's creation time. If the parent exited in between, the process ID could already name an unrelated process. The host now reads the creation time first and checks again that the named process is still its parent, so a match proves the time it read is its parent's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test's short-lived build started the host without redirecting its standard error, so the host inherited the pipe that `subprocess.run` reads to the end. The run therefore returned only after the host had exited, and the final `psutil.wait_procs` assertion never ran: a host that kept running failed the test only through the run's timeout. The build now gives the host no output pipes and reports its creation time, and the test waits for that same process to exit. Checked against a host whose parent check always succeeds: the test now fails at "the host kept running after its parent exited". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `microcosm_emitter.compatibility` defines `EmitterDescription` (what `microcosm-emitter version` prints) and `HelloResponse` (what `hello` returns); the command and the host build them by name. - Tests: with `--skip-unavailable-modules`, a host whose requested modules are all missing refuses to start, and a message or query to a skipped module is refused while the host keeps serving the others. - README and changelog fragment: only a host started by `microcosm-emitter host` answers `hello`; one started with `python -m microcosm_emitter.host` refuses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
anth-volk
added a commit
that referenced
this pull request
Oct 21, 2026
Brings in #21's release commit `8b3aa29`: both version lines of the emitter's pyproject.toml and uv.lock move to 0.4.0, CHANGELOG.md gains the 0.4.0 entry, and #21's consumed changelog fragment is deleted. No conflicts. The interface package's own version and the emitter's exact pin on it are still 0.3.0; the next commit sets them to 0.4.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 21, 2026
#21 released 0.4.0, so main's emitter is at 0.4.0 while this branch's interface package and the emitter's exact pin on it were still 0.3.0. `tools/bump-version.py --check` refused that ("Both distributions must have the same version"), and tests/test_package_names.py would fail on CI. Both are now 0.4.0, and `uv lock` records the interface at 0.4.0. With this branch's `.added` fragment, the release this merge starts publishes both distributions as 0.5.0 (`bump-version.py --check` prints "0.4.0 -> 0.5.0"). Checked: `bump-version.py --check` exits 0; tests/test_package_names.py, tests/test_workflows.py and tests/interface/test_launcher.py pass (46). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #17
First of a stack of four pull requests that move Microcosm's upload transport into the emitter (plan step 2, E1 then H1). This one makes the emitter installable on its own and runnable as the build's child process. The next pull request adds the typed interface package whose client starts this command.
What changes
microcosm-emittercommand (microcosm_emitter.cli).uv tool install microcosm-emitterinstalls it outside the build's environment.microcosm-emitter host --socket … --parent-pid …runs the existing service host, configured on standard input as before.microcosm-emitter versionprints the emitter version and accepted socket protocol versions as JSON.python -m microcosm_emitter.host(host/launcher.py:101): no separate environment, so it inherits the build's environment variables and user and finds the same Hugging Face credential (HF_TOKEN, thenHUGGINGFACE_TOKEN, then the savedhf auth logintoken,core/auth.py:105–109). PR 2 adds the launcher and the test that proves this.psutilin the build.--parent-created-atis now optional. Without it, the host reads the named process's creation time and then checks again that the process is its own parent (os.getppid()); otherwise it refuses to start. A match after the read proves the creation time is the parent's, not that of an unrelated process given the same process ID after the parent exited. Launchers that pass the creation time behave as before.hellorequest. Only a host started bymicrocosm-emitter hostanswers{"action": "hello"}: with the emitter version, the accepted protocol versions (microcosm_emitter.compatibility.SUPPORTED_PROTOCOL_VERSIONS, now(1,)) and the loaded and skipped modules, typed ascompatibility.HelloResponse. A host started withpython -m microcosm_emitter.host(the in-process launcher) answershellowith an error, as for any unknown action.--skip-unavailable-modulesstarts the host without requested modules that this emitter does not install, so a newer build can still use an older emitter's modules. A request to a skipped module is refused like one to an unknown module, and the host still refuses to start if none of the requested modules is installed. Without the flag, a missing module still stops startup.python -m microcosm_emitter.hostkeeps working for Microcosm builds pinned tomicrocosm-emitter==0.2.1.Release
The fragment is
added: merging releases the next minor version ofmicrocosm-emitterto PyPI.Validation
Red-green by commit (macOS, Python 3.14; only the test files this pull request adds or changes):
3b33e27Run the emitter host from an installed microcosm-emitter commandtests/host/test_installed_command.py,tests/test_package_names.py: 7 failed, 4 passed (2 existing tests, and 2 new guards for existing behaviour:python -m microcosm_emitter.hoststill starts, andhellowithout a description is refused)ruff checkandruff format --checkpass. CI runs the full suite.Overlap with open pull requests
Max's #5, #6 and #7 also edit
README.md; #5 also editspyproject.toml(its dev dependencies, which this does not touch). Expect at most a small README rebase.Review fixes (2026-10-20)
Each fix was written red, then green; only the test files this pull request adds or changes were run.
8f599daExpect the missing-module error in the module selection testtest_module_selection_refuses_missing_and_duplicateexpected "exactly one" for a missing module;load_moduleraisesModuleNotInstalledError. This was the CI failure on every pull request of the stack.tests/host/test_runtime.py: 1 failed, 14 passed (as in CI)33c54d2Read the parent's creation time before the final parent checkparent_processreadcreate_time()after its onlygetppid()check.tests/host/test_installed_command.py: 2 failed, 8 passed1ecadcfLet the parent-exit test see a host that outlives its parentsubprocess.run(capture_output=True)returned only after the host exited and the finalpsutil.wait_procsassertion never ran. The build now gives the host no output pipes and reports its creation time.TimeoutExpired22fca11Type the hello payload and test skipped modulesmicrocosm-emitter hostanswershello; no tests for--skip-unavailable-moduleswith every module missing or for a request to a skipped module; optionalTypedDict.TypedDicttest failed (1 failed, 11 passed). README and fragment changes need no red stepRe-run after the last commit:
tests/host/test_installed_command.py,tests/host/test_runtime.py,tests/test_package_names.py: 30 passed.tools/check-quality.shandtools/check-changelog.shpass.🤖 Generated with Claude Code