Install
$ agentstack add skill-wyattjoh-skills-executing-workflows-manually ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Executing Workflow Scripts Manually
Claude Code's Workflow tool runs orchestration scripts that fan work out to fresh-context subagents. An agent without that tool can still execute the same script: you become the orchestration engine. You interpret the JavaScript top to bottom, evaluate the glue code faithfully, and perform every agent() call as a real subtask, either by dispatching a subagent (if your harness has any) or by doing the work yourself, one task at a time.
The script is the contract. Your job is fidelity, not improvisation.
What a workflow script is
Plain JavaScript (never TypeScript). The body runs as one async function, so top-level await and a final top-level return are normal. It begins with a pure-literal export const meta = { name, description, whenToUse?, phases? } that describes the run. The rest of the file uses a small set of global functions to orchestrate subagents. Scripts have no filesystem or Node API access, and Date.now(), Math.random(), and argless new Date() are banned, so everything except agent results is deterministic.
Quick reference: construct to manual equivalent
| Construct | Engine semantics | Your manual equivalent | | ---------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | export const meta | run metadata, phases for display | announce name, description, and phase list before starting | | phase('Title') | starts a progress group | announce "Phase: Title" to the user | | log(msg) | narrator line | evaluate the string with real values and report it | | agent(prompt, opts) | fresh-context subagent; its final text is the return value | perform the prompt as an isolated subtask (rules below) | | pipeline(items, ...stages) | each item flows through all stages, no cross-item barrier | for each item in order, run all of its stages to completion, then move to the next item | | parallel(thunks) | run all thunks, wait for all; a failed thunk resolves to null | run the thunks one by one in order; a failed one contributes null | | args | the Workflow call's input value | whatever the user supplied; undefined otherwise. If the script reads args and you have none, ask before starting | | budget | { total, spent(), remaining() } token target | total is null unless the user gave you a token target; remaining() is Infinity when total is null | | workflow(ref, args) | nested workflow run | execute that script the same way, one nesting level only | | return {...} | the run's final result | evaluate the object with real values and present it as the outcome |
Execution procedure
- Read the whole script first. Identify the constants, helper functions,
schemas, and every agent() call site. Announce meta.name, meta.description, and the phase list.
- Resolve inputs. If the script references
args, confirm the value with
the user. Treat budget.total as null unless the user stated a token target, and evaluate budget-guarded code exactly as written (a while (budget.total && ...) loop with no target never runs).
- Create a run journal in a temp location outside the repo (for example
/workflow-runs//journal.md). One entry per agent() call: a sequence number, label, phase, status, and the exact return value. Key entries by the sequence number, not the label alone; labels built from a shared index can collide across calls. This is your resume state and your working memory. Never commit it.
- Interpret top to bottom like a single-threaded engine:
phase()andlog(): report to the user.const x = await agent(...): execute the subtask (next section), bind
the result.
pipeline/parallel: unroll into sequential subtasks as in the table.
Concurrency in the real engine is a wall-clock optimization only; the mandatory thing is data-dependency order, which sequential execution satisfies automatically.
- Glue JavaScript between calls (filters, flattens, grouping, string
building, conditionals, loops): evaluate it faithfully with the real values you produced. Results steer control flow, so do not guess. For gnarly glue code, it is legitimate to actually run it: write a tiny script that stubs agent() with your recorded results and executes the derivation with bun or node.
- Finish. When you reach
return, evaluate the object with real values,
record it in the journal, and present it to the user as the workflow result.
Executing an agent() call
Each agent() call is designed to run in a fresh context with only its prompt. Preserve that intent:
- Materialize the prompt exactly. Prompts are built by string
concatenation with constants and prior results (including JSON.stringify(...) of earlier structured output). Compute the final literal string. Never paraphrase, summarize, or "improve" it.
- Dispatch or perform. If your harness can spawn subagents, send the
materialized prompt verbatim as the subtask's entire instruction. If not, perform it yourself as a self-contained task: read only what the prompt names, do the work, produce the deliverable.
- Produce the return value. The subagent's final text IS the return
value, raw data rather than a user-facing message. If the prompt says "return a one-paragraph summary", the call's value is that paragraph.
- Honor
schema. Whenopts.schemais present, the return value must be
a JSON object validating against that JSON Schema (required fields, enums, nesting). Later glue code indexes into it (review.findings.length), so the shape must be exact.
- Record and release. Write the return value to the journal, keep only it
in working memory, and let go of everything else the subtask read or produced. Artifacts belong on disk where the prompt said to put them.
Handling opts:
| Option | Manual handling | | ----------------------- | ----------------------------------------------------------------------------------------------- | | label, phase | use in journal entries and progress reporting | | schema | return JSON validating against it (rule 4 above) | | model, effort | quality hints; honor if you can pick models or effort, otherwise ignore | | isolation: 'worktree' | exists to stop parallel agents clobbering files; running sequentially you may skip the worktree | | agentType | a named agent definition; if your harness has it, use it, otherwise treat as the default |
Error semantics
Match the real engine instead of aborting the run:
- A failed
parallelthunk resolves tonullin the results array; the call
itself never throws. Scripts expect this and .filter(Boolean) afterward.
- A
pipelinestage that throws drops that item tonulland skips its
remaining stages; other items continue.
- If a subtask fails, retry once; if it still fails, record
nullin the
journal and continue with the engine's null semantics. Only stop the whole run for failures the script cannot absorb (for example the single agent call whose result everything else consumes).
Context hygiene for single-context harnesses
Without subagents, every task shares your one context. To survive large workflows:
- Do tasks strictly one at a time; finish and journal each before starting the
next.
- Keep deliverables on disk, summaries in the journal, and only the current
task's inputs in focus. Re-read files when a later task needs them instead of trusting your memory of them.
- Writer and reviewer calls are separate on purpose. When one prompt writes an
artifact and a later prompt adversarially reviews it, re-read the artifact from disk and judge it only against the review prompt's criteria. Do not soften the review because you wrote the artifact.
- If the workflow is too large for one session, tell the user and propose
splitting the run across sessions, using the journal as the handoff: on resume, skip journal entries marked complete, reuse their recorded results, and recompute derived glue values from them. Subtasks that edit files are not idempotent; before re-running one whose status is uncertain, check whether the file already reflects the change.
Common mistakes
| Mistake | Correction | | ------------------------------------------------------ | -------------------------------------------------------------------------------------- | | Paraphrasing or trimming an agent prompt | The materialized string is the contract; deliver it verbatim | | Skipping a call because its result "seems predictable" | Reviews and verifications exist to be run; execute every call the control flow reaches | | Merging several agent calls into one pass | Each call is a deliberate scope and perspective boundary; keep them separate | | Assuming a budget-guarded loop runs | With no user token target, budget.total is null and the guard is false | | Forgetting later pipeline stage arguments | Every stage receives (prevResult, originalItem, index) | | Returning prose when a schema is set | Return exactly the JSON shape; glue code will index into it | | Aborting the run on one failed subtask | Apply the null semantics and continue | | Doing pipeline stages breadth-first and losing track | Depth-first per item keeps the journal and your context coherent |
References
- [references/worked-example.md](references/worked-example.md): a complete
annotated script with its full manual execution trace, including pipeline unrolling, schema handling, and the budget guard.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wyattjoh
- Source: wyattjoh/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.