Repository navigation
Document that pixi run dl is the only build inside the devcontainer #116
Description
Question
Document the one build that exists inside the devcontainer, and stop AGENTS.md
implying the host's two-install convention applies in there.
Graduated from the which-build ticket.
The decision is made; this is the writing-down.
The answer: inside, run pixi run dl and pixi run aid. There is exactly one
build in there and it is the working tree — pyproject.toml declares
devlaunch = { path = ".", editable = true } and postCreateCommand runs pixi install, so the container comes up with ./dev.sh's job already done.
The forcing constraint is devpod, not naming. dl shells out to a bare
devpod from PATH (dl.py:843,866) and refuses cleanly when it is absent
(:72). Inside the container devpod exists only at
.pixi/envs/default/bin/devpod. So a devlaunch installed anywhere else would not
merely be redundant — it would have no devpod to drive and would die on the
lookup. Corroborated independently by
the in-container prototype, whose
nested ProxyCommand names exactly that path.
./dev.sh does not work in there, and not for the reason the question
guessed: it exits at its first check because uv is absent from the container
(not in the Dockerfile, not in [tool.pixi.dependencies], not in the claude-code
feature's install). The XDG_DATA_HOME worry was moot in the other direction —
dev.sh hardcodes ${HOME}/.local/share and the container sets exactly that path.
The proposed wording is in #99's resolution comment. Take it from there — but
with the two amendments below.
Amendment 1 — drop the proposed final paragraph
#99's draft ends with a paragraph explaining that the scratch-XDG recipe is
host-only and that XDG_CONFIG_HOME is load-bearing inside the container.
Do not include it. It has been superseded by
the credentials ticket, which
established that the XDG_CONFIG_HOME half guards nothing on the host either
and is being deleted outright by
#115 rather than caveated.
Once #115 lands there is no XDG_CONFIG_HOME in the instruction to warn about, so
the paragraph would document a hazard that no longer exists. Two closed tickets
pointed opposite ways here and the later, stronger finding wins: deleting beats
caveating, which is #115's own stated reasoning and principle 2's.
Amendment 2 — fix a stale claim while you are in this file
AGENTS.md still says --version reports no provenance. That is already false on
main: PR #85 landed (dev, editable from <tree>). The new section's own example
depends on it being true, so it cannot be left contradicting itself two paragraphs
apart.
The metal obligation this ticket carries
#99 could not run these — it was a reading ticket and other agents held the host's
Docker. Before this closes, paste into the PR:
pixi run dl --versionfrom inside the container,- one
pixi run dl <repo>from inside, command -v uv || echo none, confirming theuv-absent claim on metal.
CLAUDE.md is a symlink to AGENTS.md — edit AGENTS.md.
This is a wayfinder:build ticket: go through /tdd. Most of it is prose and
does not take a unit test; say plainly in the PR which parts are covered and which
rest on the pasted transcripts, rather than inventing a test for a paragraph.
Blocked on #115 — it edits
the same section of the same file. Sequencing them avoids a conflict and makes
amendment 1 unambiguous.
Activity
blooop commentedon Aug 8, 2026
breadcrumb: Claimed and re-read
AGENTS.mdagainstorigin/main(0.0.16, with the credential-warning rewrite landed). Two facts change the shape of the work before a word is written.Amendment 1 is confirmed and is now simply the absence of a paragraph. The scratch recipe on
mainis one variable, and the section already carries its own explanation of why the second one was dropped — the credential loss it caused, weighed against therepos_dirhazard it would have guarded. There is nothing left to caveat for the container, so the draft's final paragraph does not go in.Amendment 2's stale claim is already gone. The provenance work landed its own doc edit in the same commit as the feature, so the section already tells the two builds apart by output —
dev, editable from <tree>— as well as by name. Nothing to fix; the new section can lean on it without contradiction. (The stale sentence does still exist in checkouts sitting on older commits, which is likely where the ticket read it.) Reporting this rather than manufacturing an edit.Seams I will test at. Most of this is prose and gets no unit test. Three claims the new section makes are load-bearing and checkable from the tree, so they get one small module rather than a paragraph-shaped assertion:
./dev.shrefuses, cleanly and before it touches anything, whenuvis absent — exercised by actually running the script withuvoffPATHand asserting the exit status and the message. This is the claim the container advice rests on, and it is behaviour, not prose.dev.sh's job done — the editable self-dependency and the create-time install are declared, not assumed.--version.Everything else — that
pixi runis the only working form, that no released fallback is wanted inside — rests on the metal transcripts the ticket asks for, which I will paste into the PR rather than assert in a test.blooop commentedon Aug 8, 2026
breadcrumb: Built the container and the metal contradicts the draft on its central point.
devpodis on the barePATHinside, at/usr/local/bin/devpod, and it is a working CLI — same version as the pinned one, answeringversion,provider listandlist. It is root-owned and appeared at container-create time: it is the agent binary devpod injects into every workspace it makes. So the sentence "a devlaunch installed anywhere else has no devpod to drive and dies on the lookup" is false as written, and shipping it would have put a claim inAGENTS.mdthat onecommand -vrefutes.The conclusion survives; the reason has to change, and the corrected reason is better than the original because it is about entry path rather than absence. That binary is there because devpod created this container. Start the same devcontainer through VS Code or plain
devcontainer upand nothing injects it, so a devlaunch outside the project env finds a devpod on one route in and none on another — working intermittently by how you happened to open the container, which is worse to debug than never working. Whatpixi runbuys is the devpod that is there unconditionally and is the version the tree pins, rather than whatever the host happened to inject.Two other things measured while in there. The pinned devpod and the injected one are the same version here only because the host runs the version the tree pins — they are independent, and nothing keeps them equal. And both binaries read the same
~/.devpod, so the provider state is shared; the choice of binary is not an isolation boundary and the section should not imply it is.Rewording the second paragraph before the PR. The
uvclaim and thedev.shrefusal both held exactly as described.blooop commentedon Aug 8, 2026
breadcrumb: PR #125 opened. One slice: the in-container section appended to the two-install advice, plus a small module holding its checkable claims.
What landed differs from the draft in three ways, and only one of them was planned. Amendment 1 went in as instructed — the scratch-
XDGparagraph is absent, since the recipe it caveats no longer has the variable in it. Amendment 2 turned out to be already fixed onmain: the provenance work updated that bullet in the same commit that landed the feature, so the section already tells the two builds apart by output. Nothing to edit, so nothing was edited; a check pins it shut instead, because the new section quotes that string as its own example.The unplanned one is the devpod paragraph, rewritten because building the container refuted the draft's stated reason. The corrected version turns on how you opened the container rather than on devpod being absent, which is both true and more useful — the failure it predicts is intermittence, not a clean error.
All three required transcripts are in the PR, plus the
./dev.shrefusal run for real in there and thecommand -v devpodmeasurement that forced the rewrite.dl blooop/dotfilesfrom inside went clone → workspace → ssh → exit 0 in 37s cold, three levels down.One thing recorded but not fixed: the nested
upwrote its ssh host block into the host's~/.ssh/config, because the devcontainer bind-mounts~/.ssh. Known from the in-container prototype; reconfirmed, cleaned up by hand, and left for whoever owns that leak.blooop commentedon Aug 8, 2026
breadcrumb: CI green on #125 across all four Python versions. One self-inflicted red on the way: the new test parsed
pyproject.tomlwith the stdlib TOML reader, which 3.10 does not have — the repo already depends ontomlifor exactly that reason and the test now uses it. Caught by pylint rather than by a test failure, since the local environment is new enough to have both.Stage complete: branch pushed, PR open, host left as found. Nothing outstanding on this ticket.
blooop commentedon Aug 8, 2026
breadcrumb: Reviewed on PR #125 — Approve, six non-blocking comments, nothing routed back to
/tdd. The headline call was verified rather than accepted:/usr/local/bin/devpodis present, root-owned and functional in two live devpod-created containers (so #99's draft was indeed false), and it is absent from the image those containers are built from (docker run --rm --entrypoint /bin/sh <image> -c 'command -v devpod'→ not in image; nothing in the Dockerfile or the claude-code feature installs it). That closes the half the PR asserted rather than measured — the entry-path argument is sound as written. Amendment 2 confirmed:fda3cb3is an ancestor oforigin/mainandmain'sAGENTS.mdcarries the fixed bullet; the stale sentence survives atb304cb6, where the primary checkout sits. Amendment 1 confirmed absent. Red-before-green re-run against85e27b1: exactly 3 of 7 red, as claimed. Comments are two prose nits (a0.0.16example three paragraphs below a0.0.9one; the-nextsentence arguing that names stop distinguishing the builds, which they do not) and four test-quality fixes (a source-spelling assertion, one assertion implied by its predecessor so the host-advice half is unguarded, a warning test that passes on a section saying the opposite, and two unhelpful failure modes). Host left as found —~/.ssh/configmd5 unchanged,devpod listunchanged, nowf116/wf125artifacts.blooop commentedon Aug 8, 2026
breadcrumb: review verdict approve, six non-blocking comments. Three concern test quality and I am treating them as fix-before-merge — a doc test that passes when the doc says the opposite is worse than no test, because it buys false confidence and still breaks on harmless rewording.
The reviewer measured the half this PR asserted: it probed the devcontainer image directly and found
devpod: NOT IN IMAGE(/usr/local/binholds onlycode devcontainer-info git gitk pixi scalar systemctl), with nothing in the Dockerfile or the claude-code feature installing it. So the entry-path argument is sound as written — the binary really is injected post-create and really is absent on the VS Code route. Its method note is fair: under verify on metal, shipping that half as an inference was onedocker run --rmshort.One over-generalisation in the PR body, not in
AGENTS.md: "mtime is the moment the container was created" does not hold —devlaunch-main-zovomobowas created 2026-08-07T22:36 with binary mtime Aug 8 08:42. devpod re-injects on later operations, so mtime is last injection. That strengthens the framing rather than weakening it.blooop commentedon Aug 8, 2026
breadcrumb: review round on #125 addressed in
11d9f22— all six non-blocking comments from the approval.Three of the seven doc tests passed on text saying the opposite of what they claimed to check.
test_the_provenance_example_matches_what_version_printspinned the f-string's source spelling instead of running the line that composes it, and its host-advice assertion was implied by its container one — it now feeds the real_install_provenance()a PEP 610 editable record and compares what it emits against what the doc quotes, parametrized so host and container fail independently.test_agents_md_warns_off_dev_sh_inside_the_containernow pins the bold prohibition rather than the words./dev.shanduv._container_section()names a missing heading instead of raisingValueError, and thepostCreateCommandregex accepts the argv-array form it used to misreport as absent.Prose: both
--versionexamples readdl <version> (…)so they cannot drift apart at a release (they already had,0.0.9vs0.0.16), and the-nextsentence now says the two builds would be identical rather than that naming stops distinguishing them. The PR body's "mtime is the moment the container was created" is corrected to last injection — devpod re-injects on later operations.Every changed assertion was mutated red against text that should fail it (inverted
./dev.shinstruction, changed provenance message, host-only example break, renamed heading) and green where it should stay green (atree→pathrename, an arraypostCreateCommand); transcripts are in the PR reply. CI green on11d9f22. Not merged, not closed.blooop commentedon Aug 8, 2026
breadcrumb: fixes verified, merge-ready (pending the merge train's release bump). CI green at
11d9f22.I checked the two tightened assertions directly rather than taking the report's word:
test/test_agents_doc.py:91—re.search(r"\*\*Do not run \./dev.sh`[^*]***", section). The old version asserted only that./dev.shanduv` appeared, so a section telling you to run it would have passed. It cannot now.:40-47—_heading_indexasserts with the missing heading named, instead of lettingstr.indexraiseValueError. A renamed heading now says so rather than failing every dependent test for an unrelated-looking reason.:147—postCreateCommandmatches string or argv array, so the array form stops being misreported as "declares no postCreateCommand".The mutation table's most convincing row is the negative control: renaming
tree→pathindl.pynow leaves the tests green (3 passed), where the old test broke on it. The test moved from pinning an f-string's spelling to running_install_provenance()against a real PEP 610 record — so it exercisesdl.py's composition instead of its source text.One environmental gotcha worth carrying: local pylint reports
E0611: No name '_install_provenance'because the pixi env's editable install resolves to the primary checkout, which sits atb304cb6and predatesfda3cb3where that function landed. Not a defect in the PR — a stale-checkout shadow, and the second time today it has misled someone.blooop commentedon Aug 8, 2026
Merged in #125 and shipped in v0.0.17.