feat(subos): subos-as-xpkg system (M1-M5)#296
Merged
Conversation
Mirrors upstream mcpplibs/libxpkg enum addition. Foundation for type=subos package dispatch — see .agents/docs/subos-as-xpkg-design-2026-05-16.md (Phase 0 / Task 1). Requires upstream commit "feat(xpkg): add PackageType::Subos for subos-as-xpkg" on mcpplibs/libxpkg feat/pkgtype-subos branch.
…tall
Adds xim::subos namespace mirroring the script.cppm pattern. Default
hooks:
- install: ensure install_dir + bin/ skeleton; synthesize .xlings.json
workspace from xpm.deps when tarball doesn't carry one
- config: register via xvm.add_version so the package is queryable
and uninstallable like any normal xpkg
- uninstall: remove xvm entry; on-disk payload removal is handled by
xim's standard uninstall path
Authors can override any of the three hooks by defining install()/
config()/uninstall() in the package .lua. The existing executor's
has_hook() check still routes to user code first.
Package path convention is unchanged — type='subos' packages land at
xpkgs/<namespace>-x-<name>/<ver>/, identical to xim-x-foo / scode-x-foo.
E2E test covers: install path, xpkgs layout, .xlings.json synthesis,
xvm registration. Fixture in tests/e2e/fixtures/subos_xpkg/py-demo.lua.
Refs: .agents/docs/subos-as-xpkg-design-2026-05-16.md (M1)
Extends 'xlings subos use' with --cmd <string> (and --cmd=<value>) to run a single command in the subos and exit with the command's exit code. POSIX: shell -c <cmd>; Windows: pwsh -Command / cmd /c. Works in both shell-level and sandbox modes; threaded through build_bwrap_argv_ and build_proot_argv_ to append -c <cmd>. Rejected combinations: --cmd + --global : --global persists active subos, doesn't spawn --cmd + --shell : --shell emits eval-able env code, no shell to exec E2E coverage: stdout capture, exit-code propagation, incompatible flag combinations, --cmd=<value> equals form. Refs: .agents/docs/subos-as-xpkg-design-2026-05-16.md (M3)
Adds `xlings subos new <name> --from <spec>` which forks the new subos
from either:
- a local subos (bare name, e.g. --from base-env): copies content
from subos/<base>/ to subos/<new>/
- a pkg-spec (contains ':' or '@', e.g. --from subos:py-ds@1.0.0):
locates xpkgs/<ns>-x-<name>/<ver>/; if not yet installed,
auto-invokes `xlings install <spec>` (E5: agent always 1 command)
Cross-platform copy uses reflink-where-possible (Linux btrfs/xfs,
macOS APFS clonefile); falls back to full byte copy via
std::filesystem::copy on Windows / non-COW filesystems. xpkg deps
stay shared in xpkgs/ so the fork itself is near-instant on shared
storage; the new subos's workspace inherits the base's .xlings.json.
Storage choice belongs to the fork (per E2 design): base is a recipe
that doesn't pin storage mode; user picks --storage at fork time.
copy_tree_ overlays base content, then storage/imageSize fields in
.xlings.json are re-applied so the new subos's storage wins.
E2E coverage: local fork content inheritance, fork independence
(modification isolation), pkg-spec fork with auto-install, --from=
equals form, error path for missing source.
Refs: .agents/docs/subos-as-xpkg-design-2026-05-16.md (M2, E1-E5)
…stop
Adds the keeper module (Linux-focused, cross-platform stubs) that
holds bwrap's mount namespace alive between sandboxed --cmd execs
so high-frequency agent workloads avoid per-call mount overhead.
This commit lands:
- keeper.cppm: register_pid / touch_activity / is_alive (with
stale PID cleanup) / nsenter_and_exec / stop_keeper /
should_auto_keeper predicate. POSIX headers in global module
fragment to avoid `import std;` redeclaration conflicts.
- subos.cppm: argparse for --keep / --no-keep / --ttl <sec> on
`subos use`; mutual-exclusion validation; integer-parse error
handling for --ttl.
- `xlings subos stop <name>` CLI: SIGTERM then SIGKILL fallback,
cleans .keeper.pid + .keeper.lastused. Idempotent — safe to call
when no keeper is running.
- E2E coverage: stop-no-op, --keep/--no-keep mutual exclusion,
--ttl non-integer rejection, --ttl + --no-keep parses, stale PID
file cleanup via subos stop.
The auto-spawn integration with use_sandbox_mode_ (full bwrap-fork +
nsenter dispatch on first --sandbox --cmd, with should_auto_keeper
gating per D9) is a deliberate follow-up: the primitives are wired,
the CLI surface is complete, and the auto-trigger flip is a one-line
change once bwrap-keeper fork point is validated against the matrix.
Refs: .agents/docs/subos-as-xpkg-design-2026-05-16.md (M4 + M5, D9)
Design doc records the converged subos-as-xpkg architecture across
revisions:
rev1: initial brainstorming convergence
rev2: simplification (no Lua API needed)
rev3: bring back type='subos' + default hooks; sandbox/storage
decisions; xvm-as-normal-package registration
rev4: auto-keeper with TTL=5min idle (M4); explicit overrides (M5)
Plan decomposes into 11 tasks across 5 phases (Phase 0 + M1-M5),
with parallel/sequential dependencies noted so a downstream
subagent run can fan out where the file map allows. Each task has
TDD-style checkpoints + exact file paths.
This PR's commits realize Phase 0 + M1-M5 (CLI surface complete;
auto-keeper runtime spawn deferred to follow-up).
Refs design: .agents/docs/subos-as-xpkg-design-2026-05-16.md
Refs plan: docs/superpowers/plans/2026-05-16-subos-as-xpkg.md
Pulls in the upstream Subos enum addition required by the subos-as-xpkg dispatch. Replaces the local_libxpkg dev override that was needed before openxlings/libxpkg#23 merged. Refs: mcpplibs/mcpplibs-index#13, openxlings/libxpkg#23
Includes: - feat(subos): subos-as-xpkg system (M1-M5) - type='subos' xpkg dispatch + default install/config/uninstall hooks - subos new --from <local|pkg-spec> fork with auto-install - subos use --cmd <string> non-interactive exec (POSIX + Windows) - keeper primitives + --keep/--no-keep/--ttl flags + subos stop - chore: bump mcpplibs-xpkg dep to 0.0.41 (brings PackageType::Subos)
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.
Summary
Implements the subos-as-xpkg system per design doc
.agents/docs/subos-as-xpkg-design-2026-05-16.md(rev4). Subos environments are now first-class xpkg packages withtype = "subos", forked in near-zero seconds via--from, executed non-interactively via--cmd, and accelerated for high-frequency sandbox exec via the auto-keeper primitives.Five user-facing capabilities land here (M1–M5):
type = "subos"package format + default install/config/uninstall hooksxlings install subos:py-ds@1.0.0subos use --cmd "<string>"non-interactive execxlings subos use exp --cmd "python script.py"subos stoplifecyclexlings subos stop exp--no-keep,--ttl <sec>,--keep)xlings subos use exp --sandbox --ttl 600 --cmd "..."Key design decisions
type = "subos"is a normal xpkg type, not a special schema. Packages land at the standardxpkgs/<namespace>-x-<name>/<ver>/path with no special prefix; xvm registration is normal. Authors can override any default hook by defininginstall()/config()/uninstall()in their.lua.xpkgs/; the fork only carries the small.xlings.json+ static files, so it's near-instant.--storage shared|tmpfs|imageper fork.subos stopCLI +--keep/--no-keep/--ttlflag plumbing. The auto-default behavior (storage=image|tmpfs + sandbox + Linux → spawn keeper with TTL=5min) is a deliberate one-line follow-up once we validate the bwrap-keeper fork point against the CI matrix.Dependency
Requires the upstream
mcpplibs/libxpkgPR addingPackageType::Subos:👉 openxlings/libxpkg#23
Until that merges, this PR builds via
xmake f --local_libxpkg=/path/to/libxpkgagainst the feature branch.File map
Created
src/core/xim/libxpkg/types/subos.cppm— default install/config/uninstall hooks (mirrorsscript.cppmpattern)src/core/subos/keeper.cppm— keeper primitives:is_alive(with stale PID cleanup),register_pid,touch_activity,nsenter_and_exec,stop_keeper,should_auto_keeperpredicatetests/e2e/fixtures/subos_xpkg/py-demo.lua— fixture: minimaltype = "subos"packagetests/e2e/subos_xpkg_install_test.sh— M1 e2etests/e2e/subos_xpkg_fork_test.sh— M2 e2e (local + pkg-spec fork, auto-install, isolation)tests/e2e/subos_xpkg_use_cmd_test.sh— M3 e2e (--cmd, exit-code, incompatible flags)tests/e2e/subos_xpkg_keeper_test.sh— M4+M5 e2e (subos stop, flag mutual-exclusion, stale PID cleanup).agents/docs/subos-as-xpkg-design-2026-05-16.md— design doc (rev1→rev4)docs/superpowers/plans/2026-05-16-subos-as-xpkg.md— implementation planModified
src/core/xim/index.cppm—type_to_int/int_to_typemapSubos ↔ 4src/core/xim/libxpkg/types/type.cppm— comment updated for new pkgType valuesrc/core/xim/installer.cppm— install/config/uninstall dispatch forpkgType == 4src/core/subos.cppm—new_from()export,use_spawn_shellcmd param, bwrap/proot argv builders threadcmd,subos new --from/subos stop/keeper-flag argparse, mutual-exclusion validationTest plan
What's verified locally
Out of scope (deferred, see design §11 — Future)
subos use subos:xxx --sandbox --cmd ...(cleanup/GC complexity; explicit two-step suffices for now)subos = {...}descriptor-only form (no tarball)use_sandbox_mode_(keeper module + CLI plumbed; one-line flip when ready)Commit walk
feat(xim): map PackageType::Subos to pkgType=4— schema/dispatch foundation (requires upstream PR)feat(xim): dispatch type='subos' through default install/config/uninstall— M1feat(subos): subos use --cmd <string> for non-interactive exec— M3feat(subos): subos new --from <spec> for fork from local subos or pkg— M2feat(subos): auto-keeper primitives + --keep/--no-keep/--ttl + subos stop— M4+M5docs: subos-as-xpkg design (rev4) + implementation plan— design + plan