Skip to content

Simplify container spec: single string instead of build dict#60

Merged
EiffL merged 4 commits into
mainfrom
simplify-container-spec
Apr 14, 2026
Merged

Simplify container spec: single string instead of build dict#60
EiffL merged 4 commits into
mainfrom
simplify-container-spec

Conversation

@EiffL
Copy link
Copy Markdown
Member

@EiffL EiffL commented Apr 14, 2026

Summary

  • Aligns Prism with the updated ASTRA schema where container is a single string — either an image name (e.g., python:3.9, ghcr.io/org/img:latest) that gets pulled, or a path to a Containerfile (e.g., Containerfile, containers/Dockerfile) that gets built from source
  • Removes all dict-based container spec handling ({"build": "Containerfile", "context": ".", "args": {...}}) — the runtime now detects whether to pull or build by checking if the string points to an existing file
  • Updates resolve_container_spec, resolve_container_for_slurm, get_container_status, CLI build command, asset factory, guides, templates, and tests

Test plan

  • All 315 tests pass
  • No new ruff lint errors
  • Verify prism init creates correct container: Containerfile in astra.yaml template
  • Verify prism build correctly detects Containerfile paths vs image names
  • Verify prism status shows correct container status for both cases

🤖 Generated with Claude Code

EiffL and others added 3 commits April 14, 2026 20:14
Align with updated ASTRA schema where the container field is a single
string — either an image name (pulled) or a path to a Containerfile
(built from source). The runtime detects which case via file existence.
Removes all dict-based container spec handling (ContainerBuildSpec,
build/context/args keys).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The success_criteria field no longer exists in the ASTRA spec. Removes
all references from guides, skills (prism-new, prism-build, prism-verify),
loop prompt, and eval task YAML files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ASTRA package was renamed from 'astra' to 'astra-tools' and
published to PyPI. The old git+https dependency fails because pip
detects the metadata name mismatch. Switch to the PyPI package.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@EiffL
Copy link
Copy Markdown
Member Author

EiffL commented Apr 14, 2026

@claude review this PR, pay particular attention to whether all edits have been correctly propagated

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 14, 2026

✅ Eval Results

Metric Value
Score 1.00
Build complete
Cost $1.28
Turns 70
Duration 418s
Prism 0.1.dev1+g1e4377135 (1e437713)
Results Download

Graders

✅ spec_valid (1.00)
✅ all_materialized (1.00)

Full output
b-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:07 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:08 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:08 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:08 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:08 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:09 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:09 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:09 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:10 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:10 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:10 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:10 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:11 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:11 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:11 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:48:12 httpx HTTP Request: POST https://proxy.app.daytona.io/toolbox/325bb2eb-86fa-49c0-a422-e1bbf1574ddd/files/bulk-upload "HTTP/1.1 200 OK"
18:55:12 prism.eval.sandbox Deleted sandbox for trial build-snae-0
  snae trial 0: score=1.00 complete

Prism: 0.1.dev1+g1e4377135 (HEAD 1e437713)

  Eval Results: Scores  
┏━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Task ┃     Score     ┃
┡━━━━━━╇━━━━━━━━━━━━━━━┩
│ snae │ 1.00 +/- 0.00 │
│      │ pass@k: 100%  │
└──────┴───────────────┘

   Eval Results: Cost &   
         Duration         
┏━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Task ┃ Cost / Duration ┃
┡━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ snae │      $1.28      │
│      │      418s       │
└──────┴─────────────────┘

Total: 1 trials, $1.28, 418s

Results saved to: eval-results/build-1e437713/results.json

@claude
Copy link
Copy Markdown

claude Bot commented Apr 14, 2026

Claude finished @EiffL's task in 4m 17s —— View job


PR Review: Simplify container spec

Tasks:

  • Gather context and understand request
  • Read changed source files (container.py, cli.py, assets.py)
  • Read changed test files
  • Read changed documentation/skills files
  • Check for propagation gaps across all 15 changed files
  • Post detailed review

Overall Assessment

The propagation is consistent and complete across all 15 changed files. The simplification is clean — every place that previously branched on isinstance(spec, dict) vs str has been updated to use the new _is_containerfile() helper. No stale references to the old dict format remain.

A few minor issues worth addressing:


Issues

1. ContainerStatus.extra field is dead code

src/prism/container.py:207

extra: dict[str, Any] = field(default_factory=dict)

The extra field was previously used to surface error messages when a dict spec was malformed (e.g., extra={"error": "Containerfile not found: ..."}). Now that the dict spec is gone, extra is never set by any code path, and no caller reads it (I confirmed no .extra usage anywhere in src/ or tests/). This field, and the Any import it requires, are now dead code.

Also affects: the cstatus.extra.get("error") branch was correctly removed from cli.py:1558, but the underlying dataclass field was not cleaned up.

Fix this →

2. _is_containerfile is a private function imported cross-module

src/prism/cli.py:1358

from prism.container import _is_containerfile

Importing a _-prefixed private function from another module is a code smell. Since this function is now used in both container.py and cli.py, it should be made public by removing the underscore prefix (and updating all call sites).

Fix this →

3. build_args on build_image() / build_image_podman_hpc() is now unreachable via the high-level API

src/prism/container.py:116,219

The dict spec used to allow args: {KEY: VAL} which was passed through as build_args to build_image(). Since the dict spec is gone, no high-level caller will ever pass build_argsresolve_container_spec and resolve_container_for_slurm call build_image(tag, containerfile, project_path, runtime=runtime) without build_args. The parameter and its test_build_args test remain, keeping the low-level API usable, but this represents an undocumented capability gap (users can no longer pass --build-arg values). Worth a note or a decision whether to remove the parameter or expose it via config.

4. Silent typo handling — design trade-off to document

Any string that doesn't match an existing file is silently treated as a pre-built image name. This means a typo like container: Containerfle will fail at execution time with a cryptic "image not found" error instead of at build time with "file not found". The PR description acknowledges this design but it would be worth adding a note in the resolve_container_spec docstring warning about this behavior.


Propagation Checklist

File Status
src/prism/container.py ✅ All dict branches removed; _is_containerfile used consistently
src/prism/cli.py build and status commands updated; boilerplate template correct
src/prism/dagster/assets.py ✅ All isinstance(raw, dict) / isinstance(raw, str) guards removed
tests/test_container.py ✅ All dict specs replaced with string specs; new _is_containerfile behavior covered
tests/test_assets.py ✅ Updated; local_runtime="docker" correctly added
claude/prism/guides/astra-reference.md success_criteria and dict container example removed
claude/prism/guides/prism-reference.md ✅ Container description updated
claude/prism/skills/prism-build/SKILL.md success_criteria reference removed
claude/prism/skills/prism-build/assets/loop-prompt.md success_criteria step removed
claude/prism/skills/prism-new/SKILL.md success_criteria and analysis context updated
claude/prism/skills/prism-verify/SKILL.md ✅ Success criteria section removed; report template updated
evals/tasks/snae/CLAUDE.md /prism-verify description updated
evals/tasks/snae/astra.yaml ✅ Dict spec and success_criteria removed
CLAUDE.md ✅ Key invariant updated
pyproject.toml astra-tools>=0.2.2 dependency updated

One file not changed that you may want to verify manually: claude/prism/skills/prism-migrate/SKILL.md — it mentions "Any existing container setup (Dockerfile, Containerfile)" which is fine and doesn't need updating, but worth a quick read to confirm there's no dict-format example buried in the migration guidance.


Summary

All edits are correctly propagated. The PR achieves its stated goal cleanly. The issues above are minor (dead code, naming convention, unreachable param) and none of them are blockers. The most important one to fix before merge is probably #2 (cross-module private import) since it establishes a convention the codebase has to live with.

@EiffL
Copy link
Copy Markdown
Member Author

EiffL commented Apr 14, 2026

@claude Can you fix all the issues identified in this review?

@claude
Copy link
Copy Markdown

claude Bot commented Apr 14, 2026

Claude finished @EiffL's task in 3m 15s —— View job


Fixed all review issues

Tasks:

All changes are in src/prism/container.py and src/prism/cli.py only — no test changes needed since the extra field had no test coverage and the rename is purely internal (no public-facing behavior change).
| Branch

…ntainerfile, document build_args

- Remove `extra: dict[str, Any]` field from ContainerStatus — it was never
  set or read after the dict-spec removal; also drops the now-unused `field`
  and `Any` imports
- Rename `_is_containerfile` → `is_containerfile` (remove underscore) since
  cli.py imports it cross-module; update all call sites in container.py and
  cli.py
- Add docstring note to `build_image` and `build_image_podman_hpc` that
  `build_args` is a low-level-only parameter not reachable via the high-level
  resolve API
- Add `.. warning::` note to `resolve_container_spec` about the silent
  typo-treated-as-image-name behaviour and how to catch it early

Co-authored-by: Francois Lanusse <EiffL@users.noreply.github.com>
@EiffL EiffL merged commit 6336fca into main Apr 14, 2026
4 of 6 checks passed
@aboucaud aboucaud deleted the simplify-container-spec branch May 8, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant