Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions src/command_system/workflows_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,40 @@ def _workflow_to_command(path: Path, loaded_from: str) -> Optional[PromptCommand


_ULTRACODE_DIRECTIVE = (
"The user invoked /ultracode — AUTHOR a reusable multi-agent workflow (a "
'"pipeline") for the task below and SAVE it as a slash command. Do NOT run it '
"now, and do NOT call the Workflow tool — the user will run it themselves with "
"`/<name>` (the same way `/deep-research` runs).\n\n"
"Your job right now: WRITE a new multi-agent workflow script (a reusable "
'"pipeline") for the task at the bottom of this message, and save it to a file '
"with your Write tool.\n\n"
"IMPORTANT — this is a writing task you do YOURSELF with the tools you already "
"have. There is NO \"ultracode\" tool, skill, or command to invoke or look up — "
"do NOT use ToolSearch, do NOT search for a skill, and do NOT call any "
"\"Workflow\" tool. You are not running anything; you are authoring a `.py` file "
"and stopping.\n\n"
"Steps:\n"
"1. Read `src/workflow/bundled/deep_research.py` first and mirror its exact "
"format: a top-level `meta = {\"name\": ..., \"description\": ..., \"phases\": "
"[{\"title\": ...}, ...]}` dict, then an async body that uses ONLY the injected "
"primitives — `await agent(prompt, schema=...)`, `parallel`, `pipeline`, "
"`phase`, `log`, `budget` — and ends with `return <result>`. It is sandboxed "
"Python: no `import`, no `open`, no `Date.now()`/`random` (the runtime withholds "
"them).\n"
"2. Design the workflow for the task: decompose into phases, fan out subagents "
"1. Read `src/workflow/bundled/deep_research.py` for a complete, real example of "
"the format. A workflow is sandboxed async Python shaped like:\n\n"
" meta = {\n"
" \"name\": \"<kebab-name>\",\n"
" \"description\": \"<one-line summary>\",\n"
" \"phases\": [{\"title\": \"Search\"}, {\"title\": \"Research\"}, {\"title\": \"Write\"}],\n"
" }\n"
" phase(\"Search\")\n"
" items = await agent(\"<prompt>\", schema={...}) # one subagent, returns data\n"
" researched = await parallel([agent(f\"<prompt {x}>\") for x in items]) # fan out\n"
" phase(\"Write\")\n"
" return await agent(\"<synthesize from the results above>\")\n\n"
"Use ONLY the injected primitives — `await agent(prompt, schema=...)`, "
"`parallel`, `pipeline`, `phase`, `log`, `budget` — and end with `return "
"<result>`. No `import`, no `open`, no clock/random (the sandbox withholds them).\n"
"2. Design the pipeline for the task: decompose into phases, fan out subagents "
"for the independent parts, verify, then synthesize. Give `meta.description` a "
"clear one-line summary — it becomes the slash command's description.\n"
"3. Choose a short kebab-case name (e.g. `hn-scraper`) and Write the script to "
"`.claude/workflows/<name>.py` with the Write tool (create the directory if "
"needed). The filename stem IS the command name.\n"
"4. Reply in two or three lines: confirm the workflow is saved and tell the user "
"to run it with `/<name> <args>` (runs in the background like /deep-research). "
"If the task below is empty, ask what the workflow should do instead of guessing.\n\n"
"Author and SAVE only — do not launch it.\n\n"
"clear one-line summary — it becomes the command's description.\n"
"3. Pick a short kebab-case name (e.g. `wc26-watch-guide`) and use the Write "
"tool to create `.claude/workflows/<name>.py` with the script. The filename stem "
"becomes the command name.\n"
"4. Then STOP. Reply in two or three lines: confirm the file you wrote and tell "
"the user to run it with `/<name>` (it runs in the background, like "
"/deep-research). If the task below is empty, ask what the workflow should do.\n\n"
"Write the file and stop — do NOT run the workflow.\n\n"
"Task:\n$ARGUMENTS"
)

Expand All @@ -93,7 +105,12 @@ def _ultracode_command() -> PromptCommand:
"""The ``/ultracode`` command: author a fresh workflow and SAVE it as a reusable
``/<name>`` slash command (it does **not** run — the user launches it later with
``/<name>``, exactly like ``/deep-research``). ``/deep-research`` and saved
``/<name>`` run an *existing* script; ``/ultracode`` is the *generator*."""
``/<name>`` run an *existing* script; ``/ultracode`` is the *generator*.

The directive is written as a direct imperative ("WRITE a script… with your Write
tool") and explicitly forbids hunting for an "ultracode" tool/skill — an earlier
phrasing led models to ToolSearch for a non-existent ultracode tool instead of
authoring the file themselves."""
return PromptCommand(
name="ultracode",
description="Author a multi-agent workflow (pipeline) and save it as a /<name> command",
Expand Down
10 changes: 7 additions & 3 deletions tests/test_ultracode.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,16 @@ def test_ultracode_command_directive_authors_and_saves():

cmd = _ultracode_command()
directive = cmd.markdown_content or ""
assert "AUTHOR" in directive # author a fresh workflow
assert "write" in directive.lower() # write a script yourself
assert ".claude/workflows" in directive # …saved as a /<name> command
assert "Write" in directive # via the Write tool
assert "do NOT call the Workflow tool" in directive # NOT run immediately
assert "Write tool" in directive # via the Write tool
assert "deep_research.py" in directive # format template referenced
assert "$ARGUMENTS" in directive # the task is substituted in
assert "do NOT run the workflow" in directive # author only, no auto-launch
# Forbid the tool/skill hunt that broke a live session (model ToolSearch'd for
# a non-existent "ultracode" tool instead of authoring the file itself).
assert "ToolSearch" in directive
assert "skill" in directive
# description reflects "save as a /<name> command", not "run"
desc = (cmd.description or "").lower()
assert "save" in desc and "/<name>" in desc
Expand Down