Phase 1a of the AWS host design (docs/superpowers/specs/2026-11-13-aws-ecs-host-design.md, "Host abstraction"). Refactor only; behaviour should not change.
What changed
New host module.ContainerTarget (one Docker variant today) is now the only way into a project container: one-shot, attached and detached execs, resize, exit status, uploads, archive download, is_running. The Docker variant calls the existing docker/exec.rs code.
Host-neutral exec output.AttachedExec now yields ExecChunk instead of bollard's LogOutput. docker/exec.rs converts at the boundary.
Terminal sessions moved.ExecSessionManager is now in host::sessions and holds a ContainerTarget. get_target replaces get_container_id, so image paste, file drop and the audio bridge reuse the session's own target.
Callers migrated. 14 files no longer touch bollard, docker::exec or get_docker() for container-interior work: file/inspect/terminal/auth-token/marketplace commands, auth bridge, browser view, file viewer, marketplace sync and gh login.
Boundary test.host::tests::no_container_interior_bollard_outside_the_host_layer fails on any new direct access. Its allowlist is migration_commands.rs (Docker-only) and container_watch.rs (phase 1b).
CLAUDE.md documents the host layer.
Intentional differences
Error wording. Download, backup and "run task now" errors now read Failed to start download: <host error>, Failed to start backup: <host error> and Failed to start task: <host error>. Nothing in the frontend matches on the old strings.
Not in this PR (phase 1b)
Container lifecycle and events: create/start/stop/remove and the die event stream (container_watch.rs).
Calls that still assume Docker: 21 places build ContainerTarget::docker(id) from a container id string. These are mostly public helpers whose callers (browser view commands, file viewer commands, marketplace) still pass ids. They get converted when the lifecycle code hands out targets.
Verification
cargo check --tests: no new warnings.
cargo test --lib: 911 passed, 0 failed.
Independent review of the full diff for behaviour changes (user, working dir, env, tty, stdin, stdout/stderr split, exit status, is_running, upload ownership, session bookkeeping). Its one finding was checked against the old code and was a false positive: the old scheduler exec already set /workspace.
Not exercised by hand: I haven't run the app against a live container. The terminal, file transfer, auth bridge and browser view paths are covered only by the type-level and unit tests.
Phase 1a of the AWS host design (`docs/superpowers/specs/2026-11-13-aws-ecs-host-design.md`, "Host abstraction"). **Refactor only; behaviour should not change.**
## What changed
- **New `host` module.** `ContainerTarget` (one `Docker` variant today) is now the only way into a project container: one-shot, attached and detached execs, resize, exit status, uploads, archive download, `is_running`. The Docker variant calls the existing `docker/exec.rs` code.
- **Host-neutral exec output.** `AttachedExec` now yields `ExecChunk` instead of bollard's `LogOutput`. `docker/exec.rs` converts at the boundary.
- **Terminal sessions moved.** `ExecSessionManager` is now in `host::sessions` and holds a `ContainerTarget`. `get_target` replaces `get_container_id`, so image paste, file drop and the audio bridge reuse the session's own target.
- **Callers migrated.** 14 files no longer touch bollard, `docker::exec` or `get_docker()` for container-interior work: file/inspect/terminal/auth-token/marketplace commands, auth bridge, browser view, file viewer, marketplace sync and gh login.
- **Boundary test.** `host::tests::no_container_interior_bollard_outside_the_host_layer` fails on any new direct access. Its allowlist is `migration_commands.rs` (Docker-only) and `container_watch.rs` (phase 1b).
- **CLAUDE.md** documents the host layer.
## Intentional differences
- **Error wording.** Download, backup and "run task now" errors now read `Failed to start download: <host error>`, `Failed to start backup: <host error>` and `Failed to start task: <host error>`. Nothing in the frontend matches on the old strings.
## Not in this PR (phase 1b)
- **Container lifecycle and events:** create/start/stop/remove and the `die` event stream (`container_watch.rs`).
- **Calls that still assume Docker:** 21 places build `ContainerTarget::docker(id)` from a container id string. These are mostly public helpers whose callers (browser view commands, file viewer commands, marketplace) still pass ids. They get converted when the lifecycle code hands out targets.
## Verification
- `cargo check --tests`: no new warnings.
- `cargo test --lib`: 911 passed, 0 failed.
- **Independent review** of the full diff for behaviour changes (user, working dir, env, tty, stdin, stdout/stderr split, exit status, `is_running`, upload ownership, session bookkeeping). Its one finding was checked against the old code and was a false positive: the old scheduler exec already set `/workspace`.
- **Not exercised by hand:** I haven't run the app against a live container. The terminal, file transfer, auth bridge and browser view paths are covered only by the type-level and unit tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Phase 1 of the AWS host work (docs/superpowers/specs/2026-11-13-aws-ecs-host-design.md).
- host::ContainerTarget (one Docker variant today) wraps every
container-interior operation: one-shot/attached/detached execs, resize,
exit status, uploads, archive download, is_running. It delegates to
docker/exec.rs with no behaviour change.
- AttachedExec now yields host-neutral ExecChunk instead of bollard's
LogOutput; docker/exec.rs converts at the boundary.
- ExecSessionManager moves to host::sessions and holds a ContainerTarget.
- A boundary test lists the files that still reach into containers through
bollard / docker::exec directly; follow-up commits empty it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setup-token, the viewer's poll/probe execs, the marketplace sync and the
container gh login now reach the container via host::ContainerTarget
instead of docker::exec / is_container_running. No behaviour change: same
user, working dir, env, tty and stdin attachment for every exec.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
file_commands.rs and inspect_commands.rs no longer name bollard,
docker::exec or get_docker. The archive read, running checks, attached
download/backup execs, one-shot execs, uploads and the detached
scheduler run all go through ContainerTarget, with each exec's options
(user, env, no working dir, no TTY, no stdin) and user-facing error
wording preserved.
fetch_container_file and require_running keep their container-id
signatures because file_viewer_commands.rs calls them with an id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 1a of the AWS host work: these files no longer name bollard or
docker::exec; every exec, upload and is-running check goes through
host::ContainerTarget. No behaviour change: same user, working dir, env,
tty and stdin attachment for every exec.
- auth_bridge: the poller, reconcile and PortForward hold a ContainerTarget
(AuthBridgeManager::start keeps its container_id signature).
tunnel_connection_with_prelude keeps its String signature for the
browser-view proxy and wraps the new tunnel_into_with_prelude.
- browser_view: the supervisor and viewer helpers take a ContainerTarget;
detect::detect_in is the target-taking form of detect; install.rs's
run_step uses ContainerTarget::attach with an ExecSpec equal to the old
create_attached_exec_as call. page.rs builds the target at each exec.
- terminal_commands: open_terminal_session uses ContainerTarget::for_project;
session-derived calls build ContainerTarget::docker from the session's id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ExecSessionManager::get_target replaces get_container_id, so image paste,
file drop and the audio bridge reuse the session's own target instead of
rebuilding a Docker one; the web terminal builds its target per project.
- Drop the error-prefix rewriting helper: download/backup/run-now errors now
carry the host layer's own message after their prefix.
- Remove the now-unused create_attached_exec and MAX_ONESHOT_OUTPUT re-export.
- The boundary test's allowlist is down to migration (Docker-only) and
container_watch (phase 1b). CLAUDE.md documents the host layer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jknapp
merged commit 3ec100e06c into main2026-11-13 19:12:24 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Phase 1a of the AWS host design (
docs/superpowers/specs/2026-11-13-aws-ecs-host-design.md, "Host abstraction"). Refactor only; behaviour should not change.What changed
hostmodule.ContainerTarget(oneDockervariant today) is now the only way into a project container: one-shot, attached and detached execs, resize, exit status, uploads, archive download,is_running. The Docker variant calls the existingdocker/exec.rscode.AttachedExecnow yieldsExecChunkinstead of bollard'sLogOutput.docker/exec.rsconverts at the boundary.ExecSessionManageris now inhost::sessionsand holds aContainerTarget.get_targetreplacesget_container_id, so image paste, file drop and the audio bridge reuse the session's own target.docker::execorget_docker()for container-interior work: file/inspect/terminal/auth-token/marketplace commands, auth bridge, browser view, file viewer, marketplace sync and gh login.host::tests::no_container_interior_bollard_outside_the_host_layerfails on any new direct access. Its allowlist ismigration_commands.rs(Docker-only) andcontainer_watch.rs(phase 1b).Intentional differences
Failed to start download: <host error>,Failed to start backup: <host error>andFailed to start task: <host error>. Nothing in the frontend matches on the old strings.Not in this PR (phase 1b)
dieevent stream (container_watch.rs).ContainerTarget::docker(id)from a container id string. These are mostly public helpers whose callers (browser view commands, file viewer commands, marketplace) still pass ids. They get converted when the lifecycle code hands out targets.Verification
cargo check --tests: no new warnings.cargo test --lib: 911 passed, 0 failed.is_running, upload ownership, session bookkeeping). Its one finding was checked against the old code and was a false positive: the old scheduler exec already set/workspace.🤖 Generated with Claude Code