Glossary#
Every term the rest of these docs uses without stopping to explain it, grouped by where it comes from and sorted within each group. Definitions say what the thing is first and where it bites podbench second — several of these are ordinary Kubernetes or Linux vocabulary that happens to decide something load-bearing here.
Podbench’s own words#
- agent#
The process podbench runs as PID 1 inside a debug container —
podbench agent. It writes the sshd config, the host key and theauthorized_keysat start-up, then idles and reaps orphans. Every one of its start-up steps is an ensure rather than a create, because a restarted container has a completely fresh filesystem.- blocker#
The named mechanism that denied ptrace. Several unrelated mechanisms refuse with the same EPERM — a missing CAP_SYS_PTRACE, Yama, seccomp and a mismatch between the seat’s and the target’s LSM labels (SELinux MCS categories, or AppArmor profiles) — so naming which one is the entire point of capreport.
- burnt name#
A container name that can never be used again for the life of a pod. An ephemeral container cannot be removed, restarted or edited, so once one has been created — even if it immediately died, or was rejected by the kubelet — its name is spent. Podbench therefore allocates
podbench-1,podbench-2, … and a failed rung takes a fresh name rather than retrying its own.- capability ladder#
The ordered list of rungs
attachtries. It exists because a cluster that refuses the privileged option should still get a working editor rather than an error.- capreport#
The probe that runs inside the landed seat, on that node, and reports what debugging is actually possible — and, when it is not, which of the four ptrace blockers said no. Its exit code is its verdict: 0 live attach, 10 read-only, 15 launch-only, 20 nothing. Everything
attachprints about capability comes from here, never from the spec that was submitted.- dev pod#
Iterate mode’s sacrificial clone of a running pod: same image, same volumes, same labels if you asked for them, but with the application container idled and a podbench sidecar added. It is a second copy of the workload, which is why the mode is unsafe for a singleton.
- hotfix manifest#
Not a Kubernetes manifest. A JSON file —
.podbench-hotfix.json— written at the root of the hotfix claim, recording what the fix was made against: the repo, the base commit, the base image and its digest, the venv’s interpreter version, and the commits since. A copy travels in a pod annotation so thathotfix statusneeds oneget podsand noexec.- launch-only#
The capreport verdict for a seat that can debug processes it starts, but cannot inspect the target:
/proc/<pid>/root,mapsandenvironare denied, and so is attach. It is a rung of its own because the two halves of it are independent — tracing your own descendant needs no permission at all, sopodbench dbg --launch ./progstill gives breakpoints,runand backtraces on a pod whose own memory is shut. Reported as exit code 15. The name matters: called read-only, it sends you to a sysroot that will not open; called nothing, it hides the one inner loop that works. It is the ptrace-gated paths that are gone, not the whole of/proc—cmdline,statusandfdneed no permission and answer here as they do anywhere, which is whypodbench pidsstill lists the target’s processes.- launcher#
The half of podbench that runs on your machine — the
doctor,attach,vscode,ssh-config,status,list,devandhotfixverbs. It shells out to kubectl rather than linking a Kubernetes client library, so authentication, contexts and exec credential plugins are inherited rather than reimplemented.- manifest#
A Kubernetes object as JSON or YAML. Podbench authors these itself for the dev pod rather than using
kubectl debug --copy-to. See also hotfix manifest, which is a different thing with an unfortunately similar name.- mode#
One of the three ways in. Observe is the
attachandvscodeverbs, Iterate isdev, and Hotfix ishotfix. The design documents use the mode names and the CLI uses the verbs; they refer to the same things.- origin#
The pod a dev pod was cloned from, or the workload a hotfix is applied to. It is never modified by Iterate mode, and is recorded on the clone as the
podbench.dev/originannotation.- rung#
One step of the capability ladder, and the security context that goes with it. Full is
runAsUser: 0plus CAP_SYS_PTRACE. Degraded is the target’s own uid with all capabilities dropped. Seat is whatever the namespace will admit. There is no rung between full and degraded, because a capability added to a non-root container is a silent no-op.attachreports the rung it measured, from the seat’s own/proc/self/status: the uid and gid the kernel gave the container and itsCapEff. The rung it asked for is on the ladder lines, and the two can differ in both directions — a mutating webhook that stripscapabilities.addleaves a root seat whose spec is indistinguishable from the degraded rung, and a stored spec carrying thirteen capabilities can belong to a container with none effective.A measured degraded rung is the credential match and nothing else: the seat’s uid and gid equal the target’s, with no capability effective. Both numbers, because
__ptrace_may_access()compares the three group ids as peers of the three user ids and denies on any one differing pair — which is why a 1000:0 seat beside a 1000:1000 target is the seat rung however well its uid matches, and why podbench lands a gid-corrected seat at all. The match includes a root seat beside a root target, which no PSS restricted namespace would have admitted — the label says what the seat can do, not what let it in. The authored contexts are the other half of the story and are described under PSS.Where either gid could not be read, the rung is
not measuredrather than a rung: half a comparison earns no label, and the report names what was requested instead and says which of the two numbers was missing.listandstatusreport a measured rung too, and take it without an exec: the agent writes the four numbers into the container log once, at start-up, and those verbs recover them withkubectl logs— a read, so the cost does not scale with the number of seats in a namespace. A seat whose log cannot be read, or one older than that report, isnot measured, with its requested rung on a row of its own.A rung is still not a verdict. What a seat can do is measured by capreport, and
statusreports that measurement — ornot probed, never the rung — beside each seat it lists.- seat#
A podbench container you can work in: an editor, a shell, git and a debugger, inside the cluster. An
attachseat is an ephemeral container in the live pod; adevseat is an ordinary sidecar in the clone. Both run the agent and both get the same ssh wiring.- seat identity#
Whether sshd inside a seat can resolve a login name for the uid the seat runs as. Without one, ssh is refused before a key is even looked at — see NSS. A seat whose uid the image already has an account for has one already; otherwise a live-pod seat writes its own record into
/var/lib/extrausers/passwd, which the image ships world-writable so that a seat running as the target’s uid and gid can, needing no flag and no cooperation from the pod. Adevsidecar is given a projected/etc/passwdfile instead and writes nothing. A seat that database will not serve — it ignores records below uid or gid 500 — falls back to/etc/passwd, which the image pre-seeds with a static record for every free uid under 500 so that no write is needed. Pinning the seat to group 0 to make that file writable is not offered: the gid is half of the ptrace credential match.- sidecar#
An ordinary container added beside the application in a dev pod. Unlike an ephemeral container it may declare
resources, mount volumes with subPath, and carry a readiness probe — which is why Iterate mode is built on a clone rather than on the live pod.- singleton#
A workload where a second copy is not merely wasteful but wrong: it holds a device that accepts one connection, claims a name on the network, or takes a lock. An EPICS IOC is usually all three.
attachandhotfixare safe for one;devis not, because the clone is the second copy.- spike#
A time-boxed experiment run against a real cluster to test an assumption before building on it. S1 (the ssh transport), S2 (vscode-server in an ephemeral container), S3 (gdb against a distroless target), S4 (the Python relaunch loop) and S5 (the no-capability fallback) were the Phase 0 gate, and are collated in the Phase 0 gate report — which is where most of the non-obvious code here comes from, and which wins wherever it and the design brief disagree. S6 came later and records a route not taken: suspending an Argo CD-managed workload.
- sysroot#
The target container’s filesystem as seen from the seat, at
/proc/PID/root. gdb is pointed at it so that a distroless binary’s libraries and sources resolve, with no shared mount and no cooperation from the target.
Kubernetes#
- Argo CD#
A GitOps controller. It stamps what it applied from git with the
argocd.argoproj.io/instancelabel orargocd.argoproj.io/tracking-idannotation — on the workload, not on the pods it makes. Podbench detects only those two, deliberately: the tracking key is configurable and its default collides with an ordinary Helm label, so erring toward missing a detection is safer than refusing a mode that works.- claim#
A PersistentVolumeClaim: a request for storage that a pod mounts as a volume. Hotfix mode’s claim is mounted over the application’s venv path, which is what makes a fix survive a restart. Pod volumes are immutable after creation, so a claim can never be added to a running pod — hence the deploy-time cooperation that mode asks for.
- CreateContainerConfigError#
The waiting reason the kubelet reports when it refuses a container the API server already accepted. It arrives seconds after a successful
kubectlexit, and for an ephemeral container it leaves a burnt name behind. This is the second, asynchronous half of the two ways a debug container gets refused.- distroless#
An image containing an application and its runtime dependencies and nothing else — no shell, no package manager, often no libc utilities. You cannot
execinto one usefully, which is exactly the case podbench exists for: the seat has the tools and reads the target’s filesystem through sysroot.- drift#
A live object differing from what git says it should be. Under a GitOps controller with self-heal on, anything podbench writes to a git-managed object is drift and gets reverted, usually within seconds and always without telling you.
- EndpointSlice#
The object listing the pod addresses behind a Service. A pod joins it by matching the Service’s selector and being Ready, which is why a dev pod needs a readiness probe that follows your process — without one it joins the moment it starts, while nothing is listening.
- ephemeral container#
A container added to an already-running pod, through the
pods/ephemeralcontainerssubresource. It is the mechanismattachis built on, and it has three properties that shape everything: it cannot be removed, restarted or edited (see burnt name); it may not declareresourcesat all; and it starts from the image every time, so nothing may live only in its writable layer.- eviction#
The kubelet removing a pod to reclaim a resource — most relevantly ephemeral storage. An
attachseat shares the pod’s storage budget and cannot reserve its own, and a vscode-server plus extensions is a 1.1–1.3 GB working set, so the whole pod including the workload can be evicted.- GitOps#
Managing a cluster by reconciling it against git. Iterate mode refuses outright against a GitOps-managed workload, because a Service cutover is drift on a tracked object and self-heal reverts it with no error anywhere.
- JSON patch#
A patch that applies an explicit list of operations — RFC 6902,
kubectl patch --type=json. Podbench uses it to replace a Service selector, because a merge patch would union the two maps instead: the dev pod gets added without the original being removed, which is the opposite of a cutover and invisible until half the responses are stale.- k3s#
A lightweight, single-binary Kubernetes distribution. The six spikes ran against a real 6-node k3s cluster.
- kind#
Kubernetes IN Docker — a cluster that runs inside containers on one machine. CI runs podbench’s end-to-end suite on it.
- kubectl#
The Kubernetes CLI. Podbench shells out to it for everything, including the ssh transport, so that one kubeconfig — with its contexts, proxies and exec credential plugins — serves both the API calls and the data path.
- kubelet#
The agent on each node that actually runs containers. It is the second, later voice in the two-channel refusal: the API server can accept a container the kubelet then rejects (see CreateContainerConfigError), and the two need separate handling because only the first can be caught by wrapping the API call.
- liveness probe#
A periodic check the kubelet uses to decide whether to restart a container. A process stopped at a breakpoint stops answering it, and the kubelet cannot tell that from a hang — so on a probed pod a debugging session is on a timer, and
attachprints the arithmetic before you set one.- merge patch#
A patch that unions map keys — RFC 7386,
kubectl patch --type=merge. Right for adding the hotfix provenance annotations to whatever else an object carries; wrong for a Service selector, where JSON patch is used instead.- ownerReferences#
Metadata naming the object that created this one. Podbench walks them upward — pod → ReplicaSet → Deployment — to find the workload that carries the GitOps mark, and to find the pod template that hotfix annotations must go on.
- pod-template-hash#
A label the Deployment controller puts on the pods of each ReplicaSet. Podbench deliberately strips it (and the other controller labels) from a dev pod while keeping the Service selector labels: that puts the clone in the EndpointSlice without making it a ReplicaSet member, which would otherwise get one of the two matching pods reaped.
- PSA#
- Pod Security Admission#
The built-in admission controller that enforces the Pod Security Standards on a namespace, configured with
pod-security.kubernetes.io/enforceand friends. It is what refuses a CAP_SYS_PTRACE container synchronously, inkubectl’s stderr, and so what makes the capability ladder necessary. Its wording differs between levels, so podbench matches only the one stable fragment of the message.- PSS#
- Pod Security Standards#
The three named policy levels Pod Security Admission enforces. Privileged is unrestricted; baseline blocks known escalations; restricted additionally requires non-root,
drop: ["ALL"],allowPrivilegeEscalation: falseand aRuntimeDefaultseccomp profile. Podbench’s degraded and seat rungs are authored to be admissible under restricted. That is a fact about the context podbench writes, not about the seat that lands: a measured degraded rung is a uid and gid match with no capability, and a root seat matching a root target wears it having been admitted under nothing of the kind.- readiness probe#
A periodic check the kubelet uses to decide whether a pod should receive Service traffic. Failing one removes the pod’s address from service quietly — no restart count, nothing that survives afterwards — which is why it is the deadline that matters most when you stop a process in a debugger.
- ReplicaSet#
The controller a Deployment creates to maintain a pod count. Podbench reads it while walking ownerReferences but never annotates it: the next rollout would discard the edit.
- resize subresource#
pods/resize— the in-place change of a running container’s resource limits,kubectl patch pod --subresource resize.podbench vscodeuses it to make headroom for the editor by default (--no-resizedeclines);attach --resizeexposes it for a number you choose yourself. Never fatal: the raised limit lives on the pod alone, so a rollout, scale, image bump or eviction regenerates it away silently.- RWO#
ReadWriteOnce — a volume access mode allowing one node to mount the volume for writing. The hotfix claim is RWO, which is why that mode supports exactly one replica: a second either cannot schedule or, under ReadWriteMany, races on the same checkout.
- selector#
The label query that decides which pods a Service sends traffic to.
dev --cutoverreplaces one so the dev pod alone receives traffic, and records the original on the clone so teardown can restore it exactly.- self-heal#
A GitOps controller setting that reverts drift automatically rather than only reporting it.
- Service#
The stable name and address in front of a set of pods. See selector and EndpointSlice. Podbench never joins one silently: a dev pod carrying the origin’s labels would take production traffic, so it is always behind an explicit flag.
A pod-level setting making all containers share one PID namespace, so each can see the others’ processes. A dev pod sets it; an
attachseat gets the same visibility by targeting one container instead. Under it, PID 1 is/pauserather than the workload, andpkill -fmatches processes in every container — both traps podbench is written around.- startup probe#
A probe that must succeed before the liveness probe and readiness probe begin. While it is still running it is the only deadline in force, which is why podbench works out which probe actually applies rather than listing all three.
- strategic merge patch#
Kubernetes’ own patch type, which knows that lists like
containersare keyed by name rather than by position. Podbench uses it for the resize subresource: a JSON patch would address the container by index, and silently resize the wrong one if the spec changed underneath.- subPath#
A
volumeMountfield projecting one file or directory from inside a volume, rather than the whole thing. The API server forbids it on an ephemeral container, and refuses the entire request when it sees one — which is why anattachseat can never be given a/etc/passwdfile, and adevsidecar can.
Linux, and why ptrace says no#
- /proc/PID/root#
A symlink to the root of another process’s mount namespace. Reading it gives the seat a complete view of the target container’s filesystem — rootfs and volumes — with no shared mount and no cooperation from the target. The bridge is one-directional: the seat can read the application’s filesystem, the application cannot see the seat’s, which removes several tempting workarounds.
- ambient set#
The capability set that would let a non-root process keep a capability. No container runtime populates it, which is the whole reason
capabilities.add: ["SYS_PTRACE"]beside a non-zerorunAsUseris a silent no-op: the capability reaches the bounding set and nothing else, leaving CapEff zero. Podbench refuses to author that combination rather than ship a seat that looks privileged and behaves unprivileged.- AppArmor#
A Linux security module that confines processes by profile — one of the two podbench names, beside SELinux, as the LSM blocker. ptrace is denied between two different labels, returning the same EPERM as everything else, so the report compares the seat’s with the target’s rather than judging either alone. Which module owns the label is read from
/sys:/proc/<pid>/attr/currentis a slot they share.- bounding set#
The ceiling on the capabilities a process can ever hold. A capability here but not in CapEff has no effect at all — see ambient set.
- CAP_SYS_PTRACE#
The capability that permits attaching a debugger to a process you do not own, and reading another container’s filesystem through sysroot. Podbench’s full rung asks for it; Pod Security Admission is the thing most likely to refuse.
- CapEff#
The effective capability set, readable in
/proc/PID/status.CapEff: 0on a container that asked for CAP_SYS_PTRACE is the measured symptom of the ambient set problem.- cgroup#
The kernel’s resource-grouping mechanism. Its path in
/proc/PID/cgroupcontains the container’s runtime id, which is the only attribution of a process to its container that stays correct under shareProcessNamespace and with a second podbench session attached. Podbench injects the target’s id asPODBENCH_TARGET_CIDand matches it as a substring, because the debug container’s own cgroup namespace makes the path it reads relative.- EADDRINUSE#
The error a bind gets when the address is taken. In the relaunch loop it can also appear when nothing is listening — see TIME_WAIT — so podbench says explicitly when that is what happened, rather than leaving you to suspect your code.
- EPERM#
“Operation not permitted”. Every one of the four blockers returns it, which is why a report that only prints the errno is worth nothing.
- LSM#
Linux Security Module — the kernel’s hook framework for access-control policies layered on top of the ordinary uid/gid rules. Yama, AppArmor and SELinux are all LSMs, and
security_ptrace_access_check()is the last thing__ptrace_may_access()calls: a ptrace that satisfies credentials, dumpability and CAP_SYS_PTRACE can still be refused here, with the same EPERM as everything else. That is what deniesPTRACE_MODE_READat Diamond on a seat sharing the target’s uid — established by elimination, since every other check demonstrably passes (issue #52). An LSM refusal names nothing on the way out, which is whycapreportreaching “unknown” is a real outcome rather than a defect.- NSS#
Name Service Switch — how a Linux process turns a uid into a login name, usually via
/etc/passwd. sshd resolves the name a client offers through NSS before it looks at any key, so a seat running as a uid NSS cannot resolve refuses every login withPermission denied (publickey), a message naming nothing about identity. It also breaksssh-keygen, which callsgetpwuid()whatever it is asked to do.- PID 1#
The first process in a namespace, which inherits orphans and whose exit ends the container. The agent is PID 1 in a seat, which is why it never exits over a failed start-up step — and why Iterate mode idles the application container by authoring
sleep infinityinto the spec rather than killing the live PID 1, which the kubelet would simply restart with pristine image code.- ptrace#
The system call debuggers use to attach to and inspect a running process. Whether it is permitted is the single question the capability ladder and capreport exist to answer. Without CAP_SYS_PTRACE the kernel compares credentials, and
__ptrace_may_access()compares six ids and not three —gid,egidandsgidare peers ofuid,euidandsuid, and one differing pair denies in both directions, measured. That is why a seat runs as the target’s group, why the report printsuid:gidfor both sides, and why podbench lands a corrected seat when the measurement disagrees with what it authored.- reaping#
Collecting the exit status of terminated child processes so they do not accumulate as zombies. PID 1 inherits every orphan in the namespace, so the agent does it.
- seccomp#
A kernel facility filtering which system calls a process may make. One of the four blockers: a profile can reject
ptraceitself.- SO_REUSEPORT#
A socket option letting several processes bind the same port, with the kernel splitting incoming connections between them. It is why the relaunch loop refuses to start while anything is listening: a second bind succeeds with no error and traffic is served from old and new code at once, with nothing in any log to say so.
- ss#
The socket listing tool, from
iproute2. Podbench runs it twice per relaunch — once for listeners, once for TIME_WAIT — becausess -lcannot see the second.- TIME_WAIT#
The state a closed TCP socket sits in for up to about a minute. A port with sockets in it can refuse a rebind while
ss -lshows no listener at all, so podbench warns rather than letting an EADDRINUSE look like a bug in your code.- Yama#
A Linux security module whose
ptrace_scopesetting restricts who may attach to whom: 0 is classic behaviour, 1 restricts attachment to descendants, 2 requires admin, 3 forbids it entirely. It is host-global and node-local — two nodes in one cluster can disagree by kernel flavour — which is why podbench measures it on the node it landed on and prints the node name, and why “it worked yesterday” is explicable. CAP_SYS_PTRACE overrides it.
Binaries and symbols#
These decide what a debugger can tell you once it has attached, and they fail in a way worth naming: “cannot read the file” and “the file carries no debug information” look alike from the editor and are nothing alike underneath. The first is a refusal, the second is a working session with addresses instead of source.
- BFD#
The Binary File Descriptor library, part of GNU binutils — the layer that actually parses object files. gdb,
objdump,ld,readelfandstripall read ELF through it rather than each implementing the format. So aBFD: …line is the library complaining and not gdb, which matters when deciding what to upgrade: gdb’s ability to read a binary is its binutils’ ability. gdb renders BFD’s refusals in its own words, of whichbad value—bfd_error_bad_value— is the one meaning “I parsed this far and the file does not make sense”.- build-id#
A hash the linker embeds in
.note.gnu.build-id, identifying an exact build of a binary. It is what debuginfod looks a binary up by, so a stripped binary that kept its build-id can still be given symbols, and one without it cannot. Podbench reads it when deciding what to say about a target: “no.debug_info, but the build-id is present” and “no.debug_infoand no build-id either” are different predictions about what you are about to see.- debuginfod#
A protocol and public service that serves DWARF for a build-id, so a stripped distro binary can be debugged without installing a
-dbgpackage. Needs egress andca-certificates, which is why--no-debuginfodexists. On Debian it serves symbols but not sources (report §3.2), so expect named frames and no source view.- DWARF#
The debug-information format, carried in
.debug_*sections. It is what turns addresses into file, line, variable and type — everything a source-level debugger shows beyond a raw backtrace. Its absence is not an error: gdb attaches to a binary with no DWARF perfectly well and shows disassembly and whatever names the symbol tables hold.- ELF#
Executable and Linkable Format, the object-file format on Linux. Podbench parses just enough of it by hand — the machine, the section names — to decide which debugger flavour applies, because that decision must be made from the target’s own binary rather than from the node’s architecture or from anything the user typed.
- stripped#
A binary whose symbol table, debug sections or both have been removed. Debuggable — breakpoints by address, frames from the dynamic symbol table, library names intact — just not at source level, unless debuginfod can serve the missing DWARF.
- symbol versioning#
The scheme letting one shared library export several incompatible versions of a symbol, recorded in the
.gnu.version_rand.gnu.version_dsections. Ordinarily invisible; it matters here because a BFD older than the toolchain that linked a binary can reject its.gnu.version_routright, and then the file cannot be read at all. Measured on a Debian bookworm seat (binutils 2.40) against a RHEL-family target image: the target’s own application binaries read fine, its distro binaries —/usr/bin/bashamong them — did not.
ssh, and the transport#
- ControlMaster#
The ssh feature that multiplexes further sessions over one existing connection. Podbench’s generated stanza turns it on with a
ControlPersisttimeout, which is what makes a reconnect cost 0.058 s against 0.345 s cold.- CRI#
Container Runtime Interface — the API between the kubelet and the runtime (containerd, CRI-O). Its exec streaming is what carries podbench’s ssh connection, and its one sharp edge is fd 2.
- fd 2#
File descriptor 2, standard error. Closing or replacing it in a
kubectl exec’d process makes the CRI tear down the entire exec stream, truncating stdin and stdout mid-transfer with a zero exit code. This is why sshd is run with-e(which keeps fd 2 owned and open) and-o LogLevel=ERROR(which keeps it silent), and why no wrapper may redirect it.- HostKeyAlias#
The name ssh records a host key under, independent of the hostname. Podbench keys it on the pod UID, so a re-created pod appears as a new host rather than as a man-in-the-middle warning.
- inetd mode#
sshd -i: sshd serving one connection on its own stdin and stdout instead of listening on a socket. It is what lets akubectl execchannel be the ssh transport — no listening socket in the pod, no port-forward, no pod IP, and no inbound network path of any kind.- known_hosts#
The file ssh records host keys in. Podbench writes its own under
~/.podbench/rather than touching yours, and the generated stanza pointsUserKnownHostsFileat it.- ProxyCommand#
An ssh option naming a command whose stdin and stdout carry the connection, in place of a TCP socket. Podbench’s is a
kubectl execrunning sshd in inetd mode, which is the whole network story: the outer authentication is your kubeconfig and the inner one is your ssh key.- Remote-SSH#
The VS Code extension that runs a server on a remote host and edits there over ssh. Pointing it at the generated host alias is how the editor gets into the cluster.
- sftp#
The file-transfer subsystem of ssh. It works here like everything else, because the transport is a real ssh connection rather than an emulation of one.
- sshd#
The OpenSSH server. Podbench runs it per-connection from the ProxyCommand, against a generated config file of its own rather than the image’s, so the working configuration is a reviewable artifact and the distro’s sshd is left alone.
- vscode#
The laptop verb that lands an Observe-mode seat, sizes the pod against vscode-server’s measured footprint, provisions debugpy into the target and opens the editor on the seat’s home. Both mutations are on by default —
--no-resizeand--no-provisiondecline them — which makes it the only verb that changes a running workload without being asked for a number. See resize subresource and mode.- vscode-server#
The server half of Remote-SSH, unpacked into the seat’s home on first connect. Measured at 1215 MiB in a seat carrying a real Remote-SSH session (2026-08-16) — the figure
resize.EDITOR_HEADROOMchecks this pod’s headroom against, and the one memory cost that still earns a warning. On disk a working session with extensions and a language-server index reaches 1.1–1.3 GB, which is the ephemeral-storage figure. The ~700 MiB once quoted was an S2 projection taken without a GUI client.
Python packaging#
- .pth file#
A file in
site-packagesthat Python’ssitemodule processes at start-up. A line naming a directory is added tosys.pathonly if that directory exists — with no warning when it does not, which is why an install spanning two containers’ filesystems dangles silently and surfaces much later as an unrelated-lookingModuleNotFoundError.- debugpy#
The debug adapter for Python, used to attach VS Code’s debugger to a Python process. The native equivalent is gdb.
- dist-info#
The metadata directory an install writes beside a package, recording its version, entry points and file list. An editable install bakes these in at install time, which is why changing
pyproject.tomlneeds the installer run again while changing code does not.- editable install#
An install that points at your checkout instead of copying it, so edits take effect without reinstalling —
pip install -eoruv pip install -e. It works by writing a .pth file into the interpreter’ssite-packages, which is what makes it sensitive to the mount namespace the checkout lives in.- PEP 660#
The standard defining modern editable installs. Its exec-style .pth file prints a traceback and then carries on with exit 0 when the path it names does not exist — a failure loud enough to scroll past and quiet enough to miss.
- pyvenv.cfg#
The file at the root of a venv recording which interpreter created it. In Hotfix mode it is on the claim, which makes it the one record of the interpreter that stays true across an image upgrade — so podbench reads the version from it and measures the live one separately.
- uv#
The Python package and project manager podbench’s image ships.
uv sync --frozeninstalls exactly what the lockfile says, because a dev pod that silently re-resolves dependencies is no longer running what production runs.- uvx#
uv tool run— fetch a tool and run it in one shot, leaving nothing installed. It is podbench’s canonical invocation:uvx podbench attach my-pod.- venv#
A Python virtual environment: an interpreter, a
bin/and asite-packagesof its own. Hotfix mode mounts a claim over the application’s, which is what makes a fix outlive the container — and also what makes the venv shadow the image’s after an upgrade, since itsbin/pythonis a symlink to an interpreter path inside the image.