Architecture¶
The public entry point is use_shell_session(SessionConfig(...)). The factory
selects the implementation before entering the session, including the official
config._session_cls injection point. Application code should depend on this
interface instead of constructing native adapters.
Dependency boundaries¶
| Responsibility | Modules | Tests |
|---|---|---|
| Value validation and immutable contracts | models/{commands,config,capabilities,state,results,input,privilege}; errors |
tests/models |
| Session ownership and command lifecycle | frontend/{session,execution,lease,handle,observation,operations} |
tests/frontend, tests/contracts |
| Bounded output and subscriptions | frontend/{capture,output,finalization} |
tests/frontend |
| Native process and byte transports | backends/native/{process,channels,containment,termination} |
tests/backends/native |
| Native command protocol | backends/native/{driver,preparation,syntax,bridge} |
tests/backends/native |
| Bash syntax and sudo | backends/bash/{syntax,containment,authentication,password_channel} |
tests/backends/bash |
| PowerShell and cmd syntax | backends/powershell/{syntax,driver.ps1}; backends/cmd/syntax |
native and common contract tests |
| Windows process containment | backends/windows/{containment,limits} |
tests/backends/native/test_platform_containment.py |
| Deterministic application double | backends/mock/{session,driver,scenario} |
tests/backends/mock, tests/contracts |
Quality tools live in scripts/quality; packaging and release operations live in
scripts/release. Shared test fixtures belong in tests/support. Keep shell
language details in their backend instead of branching throughout the frontend.
Value models do not start processes or perform I/O. The common frontend owns submission, queuing, cancellation, and final results. Drivers own transport resources. Both drivers implement the same protocol and feed the same bounded capture and input interfaces. Mock code cannot call native driver methods.
Each session owns one idle interpreter, one execution lease, and all its submitted
commands. Command-specific pipes isolate business input and output from shell
control messages. A bridge invokes structural processes with argv while inheriting
the shell's current directory and exported environment. Native scripts run in the
existing interpreter scope. Wrapper state uses the reserved sn_/$sn_ namespace;
Bash reserves file descriptor 9 for status messages. Scripts that corrupt the
protocol invalidate the session rather than causing transparent restart.
Windows uses IOCP named pipes and a Job Object assigned before user commands. POSIX uses private FIFOs and a new process group. Native shells are trusted: programs that deliberately escape a process group are outside that containment guarantee. Active Windows elevation is rejected.
The shared submission frontend resolves SessionConfig.sudo_password into a
captured asynchronous provider only for an elevated request without its own
provider. Both native and mock drivers use their existing authentication paths.
The configured secret stays out of child environment and configuration serialization.
Capture retains bounded tails and rolling match windows. Each file destination has a dedicated single-worker executor; transport backpressure limits outstanding writes. Subscriber queues are bounded and cannot backpressure primary capture. File bytes are called durable only after flush and fsync complete.
Tests must mock external connectivity. Filesystem tests own a TemporaryDirectory. Contract tests assert behavior through the public factory; unit tests exercise failure boundaries with narrowly scoped fakes. Integration tests assert native semantics and process cleanup instead of merely checking an echo command.
Production modules are limited to 200 code-bearing physical lines. Production classes and functions use descriptive names without underscore prefixes, except Python protocol dunders. Every function and value class uses English rST documentation with parameter, return, and intentional-exception documentation. Ruff, strict mypy, structural policy checks, and 100% combined branch coverage are release gates. Platform-specific tests contribute coverage across the OS matrix; coverage must not be lowered or platform implementations excluded to pass release.