Run SDLC Workflow
SkillDev toolsRun an SDLC delegated workflow via Archon. Wraps the archon CLI with project-aware defaults.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Run SDLC Workflow skill
What this skill tells your AI
The instructions your AI receives, as published by stevegjones/ai-first-sdlc-practices in skills/workflows-run/SKILL.md and read by ahel’s review.
Execute a named SDLC workflow via the Archon CLI.
Arguments
- First argument: workflow name (e.g.,
sdlc-parallel-review) - Remaining arguments: passed through to Archon as workflow arguments
Steps
1. Verify Archon is installed and on PATH
The upstream installer places archon at ~/.bun/bin/archon, which is
not on the default macOS PATH. Distinguish between truly missing and
"installed but not discoverable":
if command -v archon >/dev/null 2>&1; then
: # on PATH — proceed
elif [ -x "$HOME/.bun/bin/archon" ]; then
echo "Archon is installed at ~/.bun/bin/archon but that directory"
echo "is not on your PATH. For this session, run:"
echo ""
echo " export PATH=\"\$HOME/.bun/bin:\$PATH\""
echo ""
echo "For a permanent fix (recommended):"
echo " echo 'export PATH=\"\$HOME/.bun/bin:\$PATH\"' >> ~/.zshrc"
echo " # then open a new terminal"
echo ""
echo "Or re-run /sdlc-workflows:workflows-setup --health-check to"
echo "diagnose."
exit 1
else
echo "Archon is not installed. Run /sdlc-workflows:workflows-setup first."
exit 1
fi
Do NOT silently fall back to $HOME/.bun/bin/archon — that hides the
real problem (PATH misconfiguration) and the user will hit it again
the next time they open a shell. Fix the environment, not the
symptom.
2. Verify workflow exists
Run archon workflow list 2>/dev/null and check if the requested workflow name appears.
If not found:
Workflow '{name}' not found. Available workflows:
{list from archon workflow list}
To install SDLC workflows, run /sdlc-workflows:workflows-setup
2b. Preprocess for containerised execution (if workflow has team images)
Check if any node in the workflow has an image: field:
python3 -c "
import yaml
from pathlib import Path
wf = yaml.safe_load(Path('.archon/workflows/<workflow-name>.yaml').read_text())
has_images = any('image' in n for n in wf.get('nodes', []))
print('NEEDS_PREPROCESSING' if has_images else 'NATIVE')
"
If NEEDS_PREPROCESSING:
- Pre-flight image check. Extract every distinct
image:value from the workflow and verify each exists locally viadocker image inspect. Fail fast with a build hint before we do the expensive rsync + seed-commit setup — otherwise the user waits, then sees a mid-run docker error from a single node.
MISSING_IMAGES=$(python3 -c "
import yaml
from pathlib import Path
wf = yaml.safe_load(Path('.archon/workflows/<workflow-name>.yaml').read_text())
images = sorted({n['image'] for n in wf.get('nodes', []) if 'image' in n})
for img in images:
print(img)
" | while read -r img; do
[ -z "$img" ] && continue
if ! docker image inspect "$img" >/dev/null 2>&1; then
echo "$img"
fi
done)
if [ -n "$MISSING_IMAGES" ]; then
echo "Workflow references team images that are not built:"
echo "$MISSING_IMAGES" | sed 's/^/ - /'
echo ""
echo "Build the missing images before running:"
echo " • For a team image (sdlc-worker:<team-name>):"
echo " /sdlc-workflows:deploy-team <team-name>"
echo " • For sdlc-worker:base or sdlc-worker:full:"
echo " /sdlc-workflows:workflows-setup --with-docker"
exit 1
fi
This check is deliberate: we do NOT silently auto-build the missing
image. Building a team image requires a manifest the user authored.
Building base/full is the setup skill's job. Either way, the user
makes the call, not us.
- Resolve credentials:
CRED_INFO=$(python3 ${CLAUDE_PLUGIN_ROOT}/scripts/resolve_credentials.py --project-dir . --json)
CRED_TIER=$(echo "$CRED_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['tier'])")
CRED_MOUNT=$(echo "$CRED_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin).get('mount_args',''))")
CRED_CLEANUP=$(echo "$CRED_INFO" | python3 -c "import sys,json; p=json.load(sys.stdin).get('cleanup') or ''; print(p)")
# Install cleanup trap *immediately* so the temp credential file is
# removed even if preprocessing or the archon run fails/is interrupted.
# The Keychain tier creates a temp file; volume and config tiers return
# an empty CRED_CLEANUP (no-op) so the trap is safe in all tiers.
cleanup_credentials() {
if [ -n "$CRED_CLEANUP" ] && [ -f "$CRED_CLEANUP" ]; then
rm -f "$CRED_CLEANUP"
fi
}
trap cleanup_credentials EXIT INT TERM
If CRED_TIER is "none", report the error message from the resolver and stop.
- Create workspace directory with its own git root:
WORKSPACE=$(mktemp -d "${TMPDIR:-/tmp}/sdlc-run-XXXXXX")
# Extend the credential trap to also remove $WORKSPACE if we bail out
# before the user chooses what to do with it (step 6). Guarded by
# SKIP_CLEANUP so explicit "keep workspace" still wins.
cleanup_workspace_and_credentials() {
if [ -z "${SKIP_CLEANUP:-}" ] && [ -n "${WORKSPACE:-}" ] && [ -d "$WORKSPACE" ]; then
rm -rf "$WORKSPACE"
fi
cleanup_credentials
}
trap cleanup_workspace_and_credentials EXIT INT TERM
# Copy the project into the workspace, but EXCLUDE:
# - parent .git/ (we re-init below, and would otherwise inherit
# core.hooksPath, refs, and any committed secrets)
# - other git worktrees
# - heavy artefacts (node_modules, venvs, __pycache__)
# - developer secrets that live alongside a project but are NOT
# part of what the container should see: SSH keys, AWS creds,
# npm/pip tokens, Docker config, shell login files, etc.
# Prompt-injection inside the container could otherwise read any of
# these and exfiltrate via tool calls. Keep this list STRICT.
rsync -a \
--exclude='.git' \
--exclude='.worktrees/' \
--exclude='node_modules/' \
--exclude='.venv/' \
--exclude='venv/' \
--exclude='__pycache__/' \
--exclude='.env' \
--exclude='.env.*' \
--exclude='.envrc' \
--exclude='.ssh/' \
--exclude='.aws/' \
--exclude='.gcp/' \
--exclude='.azure/' \
--exclude='.kube/' \
--exclude='.docker/' \
--exclude='.npmrc' \
--exclude='.netrc' \
--exclude='.pypirc' \
--exclude='.gnupg/' \
--exclude='.keychain/' \
--exclude='.*_history' \
--exclude='secrets/' \
--exclude='credentials/' \
./ "$WORKSPACE/"
# Archon resolves cwd to the enclosing git root before discovering
# .archon/workflows/. Without a fresh git root in the workspace it
# walks up to the parent repo and fails to find the workflow. Seed
# a minimal repo so discovery stops inside $WORKSPACE. Disable hooks
# so a parent repo's pre-commit (e.g. lint gates) cannot block the
# seed commit.
(cd "$WORKSPACE" \
&& git -c core.hooksPath=/dev/null init -q \
&& git -c core.hooksPath=/dev/null add -A \
&& git -c core.hooksPath=/dev/null \
-c user.email=sdlc-workflows@local \
-c user.name=sdlc-workflows \
commit -q -m "workflow-seed" >/dev/null)
# Capture the seed SHA as our "before" reference. Step 5's diff and
# step 6's cherry-pick compare against this — NOT against any
# `git -C .` lookup, which inside a `cd "$WORKSPACE"` subshell would
# collapse to the workspace HEAD itself and report zero commits.
SEED_SHA=$(cd "$WORKSPACE" && git rev-parse HEAD)
- Preprocess the workflow INTO the workspace:
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/preprocess_workflow.py \
"$WORKSPACE/.archon/workflows/<workflow-name>.yaml" \
--output "$WORKSPACE/.archon/workflows/.generated/<workflow-name>.yaml" \
--workspace "$WORKSPACE" \
--cred-mount "$CRED_MOUNT" \
--commands-dir "$WORKSPACE/.archon/commands"
# Archon's workflow discovery recurses into `.archon/workflows/`, which
# means both the original (with `image:` nodes Archon cannot execute)
# and the preprocessed (with `bash:` nodes) are loaded keyed by the same
# filename — readdir order decides which wins. Overwrite the original
# in the workspace with the preprocessed version to make this
# deterministic.
rm -f "$WORKSPACE/.archon/workflows/<workflow-name>.yaml"
cp "$WORKSPACE/.archon/workflows/.generated/<workflow-name>.yaml" \
"$WORKSPACE/.archon/workflows/<workflow-name>.yaml"
- Run the preprocessed workflow from inside the workspace:
# Archon 1.x emits a spurious "nested Claude Code detected" warning
# when CLAUDECODE=1 is in the env, and that warning path can suppress
# workflow discovery. Unset the CC handshake vars before the call.
(cd "$WORKSPACE" \
&& env -u CLAUDECODE -u CLAUDE_CODE_SSE_PORT -u CLAUDE_CODE_IPC_FD \
archon workflow run <workflow-name> --no-worktree)
Notes:
--no-worktree— workspace isolation is managed by the containers, not by Archon's worktree provider.- The
cd "$WORKSPACE"is load-bearing: Archon resolves cwd to the enclosing git root before looking for.archon/workflows/. The fresh git in step 2 is what stops that walk. - The SSE dashboard stream on
archon serveonly observes runs launched through the server; CLI-launched runs write to SQLite but do not appear in the SSE stream. Useworkflows-status(REST or SQLite) for CLI runs.
While it runs — tell the user where to watch:
Archon ships the monitoring surfaces; our job is to name them.
Emit this block to the user as soon as archon workflow run is
launched so they know how to observe without asking:
Workflow launched. Monitoring surfaces (Archon-native):
• Live per-node lines in this terminal
"[node] Started" / "[node] Completed (duration)" on stderr.
• Archon web UI
archon serve # in another terminal
open http://localhost:3090
Full dashboard with every run, every node, every event.
(First run downloads the UI; subsequent runs start instantly.)
• CLI snapshot (no server needed)
archon workflow status # what's live right now
archon isolation list # per-run worktrees
/sdlc-workflows:workflows-status # REST + SQLite, works either way
• Container-level detail
docker ps --filter name=sdlc-worker
docker logs -f <container-id>
If the run fails part-way, Archon supports resumption:
archon workflow run <name> --resume picks up the most recent
failed run from where it stopped.
- Report artefacts — BEFORE cleanup:
The containers commit to the temp workspace's git. If we cleaned up silently the user would see "Completed" and have nothing to look at. Show what was produced first:
echo ""
echo "=== Workflow artefacts ==="
echo "Workspace: $WORKSPACE"
echo ""
echo "--- New commits in workspace (vs seed) ---"
(cd "$WORKSPACE" && git log --oneline "$SEED_SHA..HEAD") \
|| echo "(no commits beyond the seed)"
echo ""
echo "--- New or modified files ---"
(cd "$WORKSPACE" && git diff --stat "$SEED_SHA" HEAD) \
|| echo "(no diff available)"
echo ""
# U-5: Fan-in overlap warning. When two or more commits in the
# workspace touched the same file, the last writer's version won
# silently. Show a warning so the user knows what was overridden
# before they cherry-pick. This is a soft warning, not a hard fail.
OVERLAP=$(cd "$WORKSPACE" && \
git log --name-only --format="" "$SEED_SHA..HEAD" 2>/dev/null \
| sort | uniq -d)
if [ -n "$OVERLAP" ]; then
echo "⚠ Fan-in overlap: the following files were modified by"
echo " multiple workflow nodes. The last writer's version won."
echo " Review the diff before cherry-picking."
echo "$OVERLAP" | sed 's/^/ /'
echo ""
fi
- Offer the user three choices — NEVER silently discard work:
Workflow complete. What would you like to do with the results?
1. Cherry-pick commits onto your current branch (default)
2. Keep the workspace so you can inspect it: <path>
3. Discard everything (rm -rf the workspace)
Reply with 1, 2, or 3.
Default when the user is absent or replies unclearly: 1 (cherry-pick, the least surprising and the least destructive).
If option 1 — cherry-pick onto current branch:
We cannot use git cherry-pick <sha> or git commit -C <sha> because
those require the main repo to have the commit object — and the
containers committed into a separate git dir (the temp workspace's
.git/). Instead, replay each commit's diff and author metadata
explicitly:
COMMITS=$(cd "$WORKSPACE" && git log --reverse --format=%H \
"$SEED_SHA..HEAD" 2>/dev/null)
for sha in $COMMITS; do
# Apply the commit's diff to our index + working tree.
if ! (cd "$WORKSPACE" && git format-patch -1 --stdout "$sha") \
| git apply --index; then
echo "Cherry-pick of $sha failed — workspace preserved at $WORKSPACE for manual recovery."
SKIP_CLEANUP=1
break
fi
# Pull the original commit's author + message out of the workspace
# repo (where the object exists) and use them here.
AUTHOR_NAME=$(cd "$WORKSPACE" && git log -1 --format=%an "$sha")
AUTHOR_EMAIL=$(cd "$WORKSPACE" && git log -1 --format=%ae "$sha")
AUTHOR_DATE=$(cd "$WORKSPACE" && git log -1 --format=%aI "$sha")
MSG=$(cd "$WORKSPACE" && git log -1 --format=%B "$sha")
if ! GIT_AUTHOR_NAME="$AUTHOR_NAME" \
GIT_AUTHOR_EMAIL="$AUTHOR_EMAIL" \
GIT_AUTHOR_DATE="$AUTHOR_DATE" \
git commit -m "$MSG" >/dev/null; then
echo "Commit of $sha failed — workspace preserved at $WORKSPACE for manual recovery."
SKIP_CLEANUP=1
break
fi
done
[ -n "${SKIP_CLEANUP:-}" ] || rm -rf "$WORKSPACE"
If option 2 — keep: print the path and set SKIP_CLEANUP=1
so the exit trap does not destroy the workspace.
If option 3 — discard: rm -rf "$WORKSPACE".
In all three cases:
# Credential file + any workspace we chose to discard are removed by
# the trap installed in step 2. Re-running is harmless:
cleanup_workspace_and_credentials
Note: the preprocessed YAML lives inside $WORKSPACE, so it goes away with the workspace (option 3 or a failed run). Options 1 and 2 preserve the workspace intentionally.
If NATIVE (no image: nodes):
Proceed with the existing archon workflow run invocation — no preprocessing needed.
3. Run the workflow
Execute:
archon workflow run {workflow-name} {remaining-arguments}
Stream the output to the user. Report completion status when done.
4. Report results
After workflow completes, report:
- Workflow name and duration
- Node completion status (which nodes passed/failed/skipped)
- Final output (from the terminal node)
- Any errors or warnings
Long-running or multi-cycle workflows
If the workflow has nodes that take more than a few minutes, or the user is running iterative designer→dev→review cycles:
- Per-node timeout: each long node must set
timeout: <seconds>in its YAML. The default 300 s (5 min) is almost always wrong for real work. - Live progress during a long node:
archon workflow runemits per-node[name] Started/[name] Completed (duration)lines to stderr as they happen — no redirect needed to see them. For tool-level detail inside a node, add--verboseand pass it through to archon. For the container's own output (whatever the AI is printing), open a second terminal and rundocker logs -f $(docker ps -q --filter name=sdlc-worker --latest). - Cycles (designer → dev → review → designer …): use
loop.stages:— see Long-Running Workflows, Cycles, and Monitoring inCLAUDE-CONTEXT-workflows.mdfor the primary pattern, with unrolled iterations as a fallback for fixed small counts. - Monitoring surfaces (any combination): the CLI's own stderr stream (shown automatically),
/sdlc-workflows:workflows-statusfor historical + REST-backed detail,archon workflow status(what's live),archon isolation list(per-run worktrees),docker logs -f <container>(per-node output),docker events --since <epoch>(node lifecycle),docker stats(resource use). The Archon web UI (archon serveon http://localhost:3090) renders the rich per-run graph only for runs launched through the server — CLI-launched runs show up in listing but the detail pages render empty. Useworkflows-statusanddocker logsfor CLI runs. - Cost: there is no cost meter in v1 — a multi-hour cyclical run on Opus will burn meaningful tokens. Flag this to the user before launching.
Signals
- GitHub stars
- 41
- Forks
- 6
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
workflows-run- Source
- github.com/stevegjones/ai-first-sdlc-practices