Spec: project.recipe

  • Status: Draft
  • Last amended: 2026-06-19
  • Constrained by: ADR-0033, ADR-0004
  • Implements: packages/agent-tooling/src/builtins/project-recipe-tools.ts, packages/daemon/src/runtime/tool-handlers/project-recipe-handlers.ts

Purpose

The project.recipe tool auto-detects project-specific build runners (npm, bun, cargo, poetry, pdm, uv, make) and provides a high-level interface for executing common project tasks. It resolves a simple op parameter to the appropriate command for the detected runner and delegates execution to shell.bash.

This tool is a convenience layer on top of shell.bash. It is intended to be auto-injected when shell.bash is present and the operator has enabled recipe support.

Parameters

Parameter Type Required Description
op string yes The operation to run (e.g., "test", "build --release")
cwd string no Working directory, relative to project root. Default: project root.

Returns

Field Type Description
runner string The detected runner used (e.g., "npm", "cargo", "make")
command string The resolved command that was executed
stdout string Combined stdout/stderr from the PTY
stderr string Always "" — PTY merges streams
exit_code integer Process exit code
timed_out boolean Whether the process was killed due to timeout
available_tasks object Map of runner name to list of available tasks

Runner Detection

The tool scans the target directory (resolved from projectRoot + cwd) for the following project files, in order of priority:

Runner Detection Files Task Source
npm package.json scripts field
bun package.json + bun.lockb or bun.lock scripts field
cargo Cargo.toml Built-in subcommands
poetry pyproject.toml with [tool.poetry] [tool.poetry.scripts]
pdm pyproject.toml with [tool.pdm] [tool.pdm.scripts]
uv pyproject.toml with [tool.uv] or uv.lock [tool.uv.scripts] or [project.scripts]
make Makefile Target names (lines matching ^[a-zA-Z_][a-zA-Z0-9_.-]*:)

Command Resolution

  1. The first word of op is matched against each detected runner's task list.
  2. If an exact match is found, that runner is used.
  3. If no exact match is found, the first detected runner is used as a fallback.
  4. The runner's command template constructs the final command:
    • npm: npm run <op>
    • bun: bun run <op>
    • cargo: cargo <op>
    • poetry: poetry run <op>
    • pdm: pdm run <op>
    • uv: uv run <op>
    • make: make <op>

Error Handling

  • No runners detected: Returns invalid_params with message "No project runners detected in this directory."
  • Invalid op: Returns invalid_params if op is empty, missing, or not a string.
  • Path traversal: Returns invalid_params if cwd escapes the project root.
  • Shell execution failure: Returns the same error as shell.bash (e.g., shell_spawn_failed).

Security

The tool requires the same permissions as shell.bash:

  • fs: rw (the shell may write files)
  • capability: shell

Path traversal on cwd is validated against the project root boundary. The tool delegates execution to the shell.bash handler, which enforces the same security model.

Notes

  • This tool is a thin wrapper around shell.bash. It does not introduce new execution capabilities; it only adds runner detection and command resolution.
  • The available_tasks field in the response helps the model discover what operations are available for subsequent calls.
  • Auto-injection (when bash is present and recipe.enabled is true) is a DSL/compiler concern, not a handler concern.