Skip to content

feat(recipes): select a Python recipe's code environment - #213

Closed
crmapj wants to merge 2 commits into
release/0.9.0from
feat/python-recipe-code-env
Closed

crmapj wants to merge 2 commits into
release/0.9.0from
feat/python-recipe-code-env

Conversation

@crmapj

@crmapj crmapj commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Prompted by user feedback.

Adds set_recipe_code_env, a narrow Design-only direct write that selects which code environment one existing Python recipe runs with. Cobuild cannot change this selection: it limits Python recipe edits to inputs and outputs, so the stock skill had no supported path and agents were left with a raw-API fallback the skill forbids.

set_recipe_code_env(project_key, recipe_name, env_mode, env_name?)
  validate arguments                      # EXPLICIT_ENV needs env_name; other modes refuse it
  read recipe settings
    type != "python"            -> refuse, nothing saved
    no params.envSelection      -> refuse, nothing saved
  EXPLICIT_ENV and name is not a PYTHON env in list_code_envs -> refuse, nothing saved
  params.envSelection = {envMode[, envName]}   # INHERIT | EXPLICIT_ENV | USE_BUILTIN_MODE
  save (code, IO, container selection, other params saved unchanged)
  return previous_env_selection + read-back env_selection

The env-name check matters because Dataiku can store an unknown name and only fail at run time. Dataiku still enforces the project's preventOverride and the user's code-env use permission on save.

 dataiku_mcp/tools/recipes.py          + set_recipe_code_env (PROJECT_EDIT_POLICY)
 CODING_STANDARDS_AND_STRUCTURE.md     + fixed exception in the Cobuild write-routing convention
 docs/capabilities.md                  + inventory, Automation exclusions, 132 tools
 skills/dataiku-headless/
   SKILL.md                            + routing row; Automation exclusion
   references/recipes.md               + "Python Recipe Code Environment" workflow and safety rules
   references/administration/code-environments.md
-                                      recipe env selection -> Cobuild
+                                      Python recipe env selection -> set_recipe_code_env
 tests/test_recipe_code_env.py         + 20 focused tests
 tests/test_tool_surface.py, tests/test_instance_policy.py  + pinned surface and Design-only policy

Out of scope: PySpark, R, and plugin recipes (refused with a clear error), and any other recipe setting.

Evidence

Before: no Headless tool could change a Python recipe's environment; the code-environments reference routed it to Cobuild, which refuses the change.

After, automated: tests/test_recipe_code_env.py (fakes only, no live instance)

explicit env            -> only params.envSelection changes; code/IO/tags/other params identical
INHERIT / builtin       -> stale envName cleared; catalog not queried
unknown or R env name   -> ValueError, save_calls == 0, state identical
r/pyspark/sql/sync/plugin recipe -> ValueError, nothing saved, catalog not queried
missing envSelection    -> ValueError, nothing saved
bad argument combos     -> ValueError before any SDK call
rejected save           -> state identical
MCP schema              -> unknown env_mode rejected; Automation denied via instance-policy contract

Local gates on this head: uv sync --locked, uv run pre-commit run --all-files (all hooks pass), uv run pytest (854 passed), uv build plus wheel import smoke on Python 3.12, cz check on the branch.

After, live: run against a personal Design node on DSS 15.0.0 through the real stdio launcher (uv run --locked --script runtime/run_mcp.py --transport stdio), calling the registered tools over MCP. The test used a synthetic scratch project with a three-row uploaded dataset and one Python recipe. An existing Python environment was only selected, never modified.

EXPLICIT_ENV <existing py3.10 env> -> read-back matches; run_recipe completed; output python_version = 3.10
USE_BUILTIN_MODE                   -> read-back matches; run_recipe completed; output python_version = 3.12
INHERIT                            -> read-back matches; run_recipe completed; output python_version = 3.12
unknown env name                   -> refused; recipe definition and code identical
env_name with INHERIT              -> refused before any SDK call
after all changes                  -> code, inputs, outputs, containerSelection, other params unchanged

Merge Danger

Door: two-way

The tool only adds a capability. Reverting removes it; recipes changed through it keep a valid selection that the UI can change back.

Blast Radius: narrow

A call rewrites one Python recipe's environment selection. Dataiku saves the whole recipe, so an edit someone else makes to that recipe between the tool's read and write is lost (documented in the skill, same as set_container_exec_config). The catalog grows by one tool (132).

Shared files with #214 (Python-script scenarios): both PRs edit the tool total in docs/capabilities.md, the Automation exclusion lists, the routing convention, and the pinned tool tests. The diffs are independent, but whichever merges second needs a small textual rebase (134 tools in total).

🤖 Generated with Claude Code

Add set_recipe_code_env, a narrow Design-only direct write that changes only
params.envSelection of one existing Python recipe (INHERIT, EXPLICIT_ENV, or
USE_BUILTIN_MODE). Cobuild cannot change this selection.

The tool refuses non-Python recipes, recipes without a selection, and names
that are not Python environments on the instance before saving, then returns
the previous and read-back selections. Routing convention, capability matrix,
tool-surface contract, and the stock skill references are updated together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Title the tool for Python recipes, which are the only type it accepts,
make the missing-selection test cases explicit, and reflow the Automation
paragraph in the root skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@crmapj
crmapj requested a review from pmasiphelps November 9, 2026 15:26
@crmapj

crmapj commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Makes more sense to have this in cobuild directly. Logged as FR & this can be closed.

@crmapj crmapj closed this Nov 9, 2026
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