pub struct ContainerPlan {
pub name: String,
pub image: String,
pub home: Option<Home>,
pub code: PathBuf,
pub assets: PathBuf,
pub assets_access: Access,
pub network: Network,
pub window: Option<&'static Desktop>,
pub bridge: Option<Bridge>,
pub browser: Option<PathBuf>,
pub guidance: Option<HarnessKind>,
pub graphify: bool,
}Expand description
A container QCode keeps for a workspace: everything needed to create it and to enter it.
One plan per workspace for the plain shell (ContainerPlan::base) and one per profile the
workspace carries (ContainerPlan::profile).
Fields§
§name: StringThe container’s name, which is how QCode finds it again after a restart.
image: StringThe image it is created from.
home: Option<Home>The workspace’s own copy of the profile’s home, mounted at HOME_DIR, for a profile
container; the base container has none because no harness lives in it.
code: PathBufThe workspace’s own files on the host, mounted writable at CODE_DIR.
assets: PathBufThe workspace’s other material on the host, mounted at ASSETS_DIR.
assets_access: AccessWhether the container may write to ASSETS_DIR.
network: NetworkWhether the container reaches the network.
window: Option<&'static Desktop>The window this container opens, for the container of a desktop profile; None for every
container a tab enters with a terminal.
bridge: Option<Bridge>The bridge between the workspace’s tabs, for a profile container: the workspace’s
Containers/MCP/ on the host, mounted read-only at MCP_DIR, and the harness whose
settings the bridge’s server is registered in. The base container has none, because no
harness runs in it.
browser: Option<PathBuf>Where a window’s container leaves the web addresses it wants opened: the workspace’s
Containers/Browser/ on the host, mounted writable at desktop::signin::OPEN_DIR.
None for every container that opens no window.
guidance: Option<HarnessKind>The harness whose instruction files in the workspace are brought up to date when the
container comes up — graphify’s section and hooks, and QCode’s own section — for a profile
on QCode high; None for every other container, which leaves the workspace’s files alone.
graphify: boolWhether graphify is in the profile’s image, so that its map is built in the workspace when the container comes up, and, for a profile on QCode high, its installer runs there. False for the base container and for a profile on base or one that went without graphify.
Implementations§
Source§impl ContainerPlan
impl ContainerPlan
Sourcepub fn base(workspace: &str, paths: &WorkspacePaths) -> Self
pub fn base(workspace: &str, paths: &WorkspacePaths) -> Self
The workspace’s plain shell container: the base image, the workspace’s own folders, and no harness home because no harness runs in it.
Sourcepub fn profile(
workspace: &WorkspaceId,
paths: &WorkspacePaths,
profile: &Profile,
) -> Self
pub fn profile( workspace: &WorkspaceId, paths: &WorkspacePaths, profile: &Profile, ) -> Self
The container one profile of the workspace lives in: the profile’s image, the profile’s permissions and the workspace’s own copy of the profile’s home.
Sourcepub fn window(
workspace: &WorkspaceId,
paths: &WorkspacePaths,
profile: &Profile,
) -> Option<Self>
pub fn window( workspace: &WorkspaceId, paths: &WorkspacePaths, profile: &Profile, ) -> Option<Self>
The container the window of a desktop profile is open in: the same image, permissions and home volume as that profile’s command-line container would have, under a name of its own.
A window gets a container to itself rather than being started inside the long-lived one. Then the container’s only program is the application: “the window closed” and “the container ended” become one fact, which the engine will tell QCode by itself, and nothing has to ask a compositor what is on screen. The two can stand side by side on the same home volume, so a profile’s window and its command-line tabs share their settings and history.
The bridge comes along, because the agent inside the window is an agent like any other: it starts the same server and asks over the same socket. Only the way back is missing, there being no prompt on a window to type an answer into.
None for a profile whose harness draws in a terminal.
Sourcepub fn create(&self, engine: &Engine, user: HostUser) -> EngineCommand
pub fn create(&self, engine: &Engine, user: HostUser) -> EngineCommand
The command that creates the container, without starting it. The container carries the
digest of this plan in PLAN_LABEL.
Sourcepub fn digest(&self, engine: &Engine, user: HostUser) -> String
pub fn digest(&self, engine: &Engine, user: HostUser) -> String
What tells this plan from any other: a digest of the command that creates its container,
label aside. A container made from another plan (other mounts, another network, a bridge
it did not have yet) carries another digest, which is how ensure_running knows to make
it again.
Sourcepub fn enter(&self, engine: &Engine, command: &[&str]) -> EngineCommand
pub fn enter(&self, engine: &Engine, command: &[&str]) -> EngineCommand
The command that runs command inside the container, attached to a terminal.
This is the only command a tab ever spawns, which is what keeps every tab inside a container: the program is an argument of the engine, never something started here.
Sourcepub fn enter_with(
&self,
engine: &Engine,
command: &[&str],
env: &[(&str, &str)],
) -> EngineCommand
pub fn enter_with( &self, engine: &Engine, command: &[&str], env: &[(&str, &str)], ) -> EngineCommand
ContainerPlan::enter with environment variables for the program, as (name, value).
Sourcepub fn open_window(
&self,
engine: &Engine,
user: HostUser,
display: &Display,
seccomp: Option<&Path>,
) -> Option<EngineCommand>
pub fn open_window( &self, engine: &Engine, user: HostUser, display: &Display, seccomp: Option<&Path>, ) -> Option<EngineCommand>
The command that opens the window, given what this machine offers it and, for the engine
that needs one, the seccomp profile at seccomp.
None for a plan that opens no window. Every option and why it is there is in
crate::engine::RunWindow and in crate::desktop; the shape of the call is the trial’s, measured.
Sourcepub fn raise_window(&self, engine: &Engine) -> Option<EngineCommand>
pub fn raise_window(&self, engine: &Engine) -> Option<EngineCommand>
The command that asks the open window to show itself: the application started a second time inside the container it already runs in.
A Wayland application cannot raise its own window without an activation token from the compositor, and QCode, being a terminal application, has none to hand it. What this does is what a second start of an editor of this family does: it finds the instance already running on the same data folder, tells it, and exits. Whether the window then comes forward or is only marked as asking for attention is the compositor’s to decide, and it differs between them; either way the person is pointed at the window they asked for.
None for a plan that opens no window.
Sourcepub fn end_tab(&self, engine: &Engine, token: &str) -> EngineCommand
pub fn end_tab(&self, engine: &Engine, token: &str) -> EngineCommand
The command that ends, inside this container, every process the tab whose token is token
started: its harness, the relay in front of it, and whatever those started in turn. Each of
them carries the tab’s token in its environment, and nothing else does.
Closing a tab stops the engine’s command that was attached to its terminal, but the engine leaves what that command started inside the container running: in the endurance trial (2026-09-24) a closed tab’s Claude Code and relay were still running twenty-five minutes later, able to go on working and spending, and holding the relay’s port so that the tab could not be opened again.
Sourcepub fn open_page(&self, engine: &Engine, address: &str) -> Option<EngineCommand>
pub fn open_page(&self, engine: &Engine, address: &str) -> Option<EngineCommand>
The command that shows address in the sign-in window, inside the container the window
is open in: localhost there is where the application waits for the sign-in to come
back. Started with the application’s own flags, so it reaches the same compositor.
None for a plan that opens no window.
Trait Implementations§
Source§impl Clone for ContainerPlan
impl Clone for ContainerPlan
Source§impl Debug for ContainerPlan
impl Debug for ContainerPlan
impl Eq for ContainerPlan
Source§impl PartialEq for ContainerPlan
impl PartialEq for ContainerPlan
impl StructuralPartialEq for ContainerPlan
Auto Trait Implementations§
impl Freeze for ContainerPlan
impl RefUnwindSafe for ContainerPlan
impl Send for ContainerPlan
impl Sync for ContainerPlan
impl Unpin for ContainerPlan
impl UnsafeUnpin for ContainerPlan
impl UnwindSafe for ContainerPlan
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more