From e38c765aeb5f6af3c4aa6d5a94d57547c79ae1b9 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Fri, 24 Apr 2026 23:37:08 -0400 Subject: [PATCH 01/20] =?UTF-8?q?Ralph=20iteration=202:=20**Replace=20proc?= =?UTF-8?q?ess.exit()=20with=20process.exitCode=20plus=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Replace process.exit() with process.exitCode plus safety-net timeout in mini-ralph-cli.js** --- scripts/mini-ralph-cli.js | 6 ++++-- scripts/ralph-run.sh | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/scripts/mini-ralph-cli.js b/scripts/mini-ralph-cli.js index 0b48497..e12148a 100755 --- a/scripts/mini-ralph-cli.js +++ b/scripts/mini-ralph-cli.js @@ -227,13 +227,15 @@ async function main() { ); } - process.exit(result.completed ? 0 : 1); + process.exitCode = result.completed ? 0 : 1; + setTimeout(() => process.exit(result.completed ? 0 : 1), 5000).unref(); } catch (err) { process.stderr.write(`[mini-ralph] error: ${err.message}\n`); if (opts.verbose && err.stack) { process.stderr.write(err.stack + '\n'); } - process.exit(1); + process.exitCode = 1; + setTimeout(() => process.exit(1), 5000).unref(); } } diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index c0bf3e1..7d19f79 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -1,6 +1,27 @@ #!/bin/bash -VERSION="1.0.0" +resolve_version() { + local pkg_json="$SCRIPT_DIR/../package.json" + if [[ ! -f "$pkg_json" ]]; then + echo "Error: package.json not found at $pkg_json" >&2 + exit 1 + fi + if [[ ! -r "$pkg_json" ]]; then + echo "Error: package.json not readable at $pkg_json" >&2 + exit 1 + fi + local version + version=$(node -e "console.log(require('$pkg_json').version)" 2>/dev/null) || { + echo "Error: Failed to read version from $pkg_json" >&2 + exit 1 + } + if [[ -z "$version" ]]; then + echo "Error: Empty version read from $pkg_json" >&2 + exit 1 + fi + echo "$version" +} +VERSION="" # Detect OS for cross-platform compatibility detect_os() { @@ -55,6 +76,7 @@ get_realpath() { } SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VERSION=$(resolve_version) LOCAL_NODE_BIN="$SCRIPT_DIR/../node_modules/.bin" # Allow tests to inject a mock by setting MINI_RALPH_CLI_OVERRIDE in the environment MINI_RALPH_CLI="${MINI_RALPH_CLI_OVERRIDE:-$SCRIPT_DIR/mini-ralph-cli.js}" @@ -108,6 +130,7 @@ CHANGE_NAME="" MAX_ITERATIONS="" NO_COMMIT=false SHOW_STATUS=false +SHOW_VERSION=false ADD_CONTEXT="" CLEAR_CONTEXT=false ERROR_OCCURRED=false @@ -164,6 +187,7 @@ OPTIONS: --no-commit Suppress automatic git commits during the loop --verbose, -v Enable verbose mode for debugging --quiet Suppress the per-iteration progress stream + --version Print the version and exit --help, -h Show this help message OBSERVABILITY AND CONTROL: @@ -228,6 +252,10 @@ parse_arguments() { SHOW_HELP=true shift ;; + --version) + SHOW_VERSION=true + shift + ;; *) echo "Error: Unknown option: $1" usage @@ -1085,6 +1113,11 @@ main() { set -e parse_arguments "$@" + if [[ "$SHOW_VERSION" == true ]]; then + echo "$VERSION" + exit 0 + fi + log_verbose "Starting ralph-run v$VERSION" log_verbose "Change name: ${CHANGE_NAME:-}" From 14d7d5a480c70f6feb148255aa1933cacf5366f7 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Fri, 24 Apr 2026 23:38:36 -0400 Subject: [PATCH 02/20] =?UTF-8?q?Ralph=20iteration=203:=20**Add=20wait-for?= =?UTF-8?q?-tee=20drain=20and=20explicit=20exit=20code=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Add wait-for-tee drain and explicit exit code capture in ralph-run.sh** --- scripts/ralph-run.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 7d19f79..18401f3 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -1056,8 +1056,9 @@ execute_ralph_loop() { { node "$MINI_RALPH_CLI" "${mini_ralph_args[@]}" } > >(tee "$stdout_log") 2> >(tee "$stderr_log") - - return $? + local node_exit_code=$? + wait + return $node_exit_code } From bc9a9d5d818da63804fea00b2b59eac414fb3594 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 00:29:22 -0400 Subject: [PATCH 03/20] =?UTF-8?q?Ralph=20iteration=204:=20**Freeze=20the?= =?UTF-8?q?=20`check=5Fralphified()`=20detection=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Freeze the `check_ralphified()` detection function** --- scripts/ralph-run.sh | 93 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 18401f3..2d563e3 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -1110,6 +1110,99 @@ run_observability_command() { esac } +ralphify_init() { + local bp_file="$SCRIPT_DIR/../OPENSPEC-RALPH-BP.md" + local config_file="openspec/config.yaml" + local agents_file="AGENTS.md" + + if ! git rev-parse --git-dir > /dev/null 2>&1; then + log_error "Not a git repository. Please run: git init" + return 1 + fi + + if [[ ! -d "openspec" ]]; then + log_error "openspec/ directory not found. Please run: openspec init" + return 1 + fi + + if [[ ! -f "$bp_file" ]]; then + log_error "OPENSPEC-RALPH-BP.md not found at $bp_file" + log_error "Package installation may be incomplete. Run: npm install" + return 1 + fi + + if ! grep -q "Ralph Wiggum" "$config_file" 2>/dev/null; then + cat >> "$config_file" << 'RALPH_CONFIG' + +# --- Ralph Wiggum --- +# This project uses the Ralph Wiggum method for iterative development. +# See OPENSPEC-RALPH-BP.md for the detailed authoring guide shipped with spec-and-loop. +context: | + This project follows the Ralph Wiggum method for task authoring. + Read OPENSPEC-RALPH-BP.md before generating OpenSpec artifacts. + Verify proposals against the Ralph checklist before approval. +rules: + proposal: + - Include explicit scope, non-goals, and first-rollout boundaries + - Resolve all policy decisions before implementation tasks + tasks: + - Use the task template from OPENSPEC-RALPH-BP.md + - Each task has one dominant outcome and one verification cluster + - Include explicit stop-and-hand-off conditions + design: + - Do not leave core policy choices unresolved + - Specify algorithms, config shapes, and failure semantics +RALPH_CONFIG + log_verbose "Updated $config_file with Ralph Wiggum rules" + else + log_verbose "Ralph Wiggum rules already present in $config_file" + fi + + if ! grep -q "Ralph Wiggum Compliance" "$agents_file" 2>/dev/null; then + cat >> "$agents_file" << 'RALPH_AGENTS' + +## Ralph Wiggum Compliance + +This project follows the Ralph Wiggum method for iterative OpenSpec development. + +Before generating any OpenSpec artifacts, you MUST: +- Read `OPENSPEC-RALPH-BP.md` in the project root +- Verify proposals against the Ralph authoring checklist +- Ensure tasks use the task template with objective done-when conditions +- Include explicit stop-and-hand-off conditions in every task +RALPH_AGENTS + log_verbose "Updated $agents_file with Ralph Wiggum compliance section" + else + log_verbose "Ralph Wiggum compliance section already present in $agents_file" + fi + + log_info "Project ralphified successfully. Proposals will now follow Ralph Wiggum best practices." + return 0 +} + +check_ralphified() { + local config_file="openspec/config.yaml" + local agents_file="AGENTS.md" + + if [[ ! -f "$config_file" ]]; then + return 1 + fi + + if [[ ! -f "$agents_file" ]]; then + return 1 + fi + + if ! grep -q "Ralph Wiggum" "$config_file" 2>/dev/null; then + return 1 + fi + + if ! grep -q "Ralph Wiggum Compliance" "$agents_file" 2>/dev/null; then + return 1 + fi + + return 0 +} + main() { set -e parse_arguments "$@" From 8cda20945aeb25cc6add5f45f66b831dc800629d Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 00:33:21 -0400 Subject: [PATCH 04/20] Ralph iteration 5: **Wire the `init` subcommand routing in main()** Tasks completed: - [x] **Wire the `init` subcommand routing in main()** --- scripts/ralph-run.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 2d563e3..4c617ce 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -133,6 +133,7 @@ SHOW_STATUS=false SHOW_VERSION=false ADD_CONTEXT="" CLEAR_CONTEXT=false +SUBCOMMAND="" ERROR_OCCURRED=false CLEANUP_IN_PROGRESS=false @@ -190,6 +191,9 @@ OPTIONS: --version Print the version and exit --help, -h Show this help message +SUBCOMMANDS: + init Configure the project for Ralph-friendly artifact generation + OBSERVABILITY AND CONTROL: --status Print the current loop status dashboard and exit --add-context Add pending context to inject into the next iteration and exit @@ -256,6 +260,10 @@ parse_arguments() { SHOW_VERSION=true shift ;; + init) + SUBCOMMAND="init" + shift + ;; *) echo "Error: Unknown option: $1" usage @@ -1212,6 +1220,15 @@ main() { exit 0 fi + if [[ "$SUBCOMMAND" == "init" ]]; then + if [[ -n "$CHANGE_NAME" ]]; then + log_error "Cannot use --change with the init subcommand" + exit 1 + fi + ralphify_init + exit $? + fi + log_verbose "Starting ralph-run v$VERSION" log_verbose "Change name: ${CHANGE_NAME:-}" From ba313b473f73c2e5d65e2cfa87739b9f66c4b754 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 00:35:03 -0400 Subject: [PATCH 05/20] =?UTF-8?q?Ralph=20iteration=206:=20**Implement=20th?= =?UTF-8?q?e=20interactive=20ralphify=20guard=20and=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Implement the interactive ralphify guard and warning** --- scripts/ralph-run.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 4c617ce..1c5bc02 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -1211,6 +1211,66 @@ check_ralphified() { return 0 } +show_ralphify_warning() { + local change_name="$1" + + cat >&2 << 'WARNING_BOX' +┌─────────────────────────────────────────────────────────────────────┐ +│ │ +│ WARNING: Project not configured for Ralph Wiggum best practices │ +│ │ +│ This project has not been ralphified. Proposals and artifacts │ +│ may not follow Ralph Wiggum conventions. │ +│ │ +│ It is recommended to run: ralph-run init │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +WARNING_BOX + + while true; do + echo "" >&2 + echo "Choose an option:" >&2 + echo " [A] Run ralphify init and redo the proposal, then continue" >&2 + echo " [C] Continue without init" >&2 + echo " [Q] Quit" >&2 + printf "Enter choice: " >&2 + read -r choice <&2 + + case "$choice" in + [Aa]) + log_info "Running ralphify init..." + if ! ralphify_init; then + log_error "ralphify init failed. Aborting." + exit 1 + fi + + local change_dir="openspec/changes/$change_name" + if [[ -f "$change_dir/proposal.md" ]]; then + rm "$change_dir/proposal.md" + log_info "Deleted proposal.md for redo" + fi + + log_info "Invoking opencode to regenerate proposal..." + opencode -p "/opsx-continue $change_name" || true + + log_info "Returning to loop execution..." + return 0 + ;; + [Cc]) + log_info "Continuing without Ralph Wiggum configuration." + return 0 + ;; + [Qq]) + log_info "Exiting." + exit 0 + ;; + *) + echo "Invalid choice '$choice'. Please enter A, C, or Q." >&2 + ;; + esac + done +} + main() { set -e parse_arguments "$@" @@ -1272,6 +1332,15 @@ main() { validate_git_repository validate_dependencies + # Ralphify guard: check if project is configured for Ralph Wiggum best practices + if ! check_ralphified; then + if [[ -z "$CHANGE_NAME" ]]; then + CHANGE_NAME=$(auto_detect_change) + log_info "Auto-detected change for ralphify guard: $CHANGE_NAME" + fi + show_ralphify_warning "$CHANGE_NAME" + fi + if [[ -z "$CHANGE_NAME" ]]; then CHANGE_NAME=$(auto_detect_change) log_info "Auto-detected change: $CHANGE_NAME" From 7019abb14ae41500c5cc7af0ef4f58804bd0b5c2 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 00:37:11 -0400 Subject: [PATCH 06/20] =?UTF-8?q?Ralph=20iteration=207:=20**Inject=20OPENS?= =?UTF-8?q?PEC-RALPH-BP.md=20into=20the=20prompt=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Inject OPENSPEC-RALPH-BP.md into the prompt manifest when ralphified** --- scripts/ralph-run.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 1c5bc02..44ea100 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -844,6 +844,15 @@ EOF if [[ -n "$agents_line" ]]; then manifest_body+=$'\n'"$agents_line" fi + + # Append Ralph best practices guide if project is ralphified + if check_ralphified; then + local bp_path + bp_path=$(get_realpath "$SCRIPT_DIR/../OPENSPEC-RALPH-BP.md") + if [[ -n "$bp_path" ]]; then + manifest_body+=$'\n'"- $bp_path (Ralph best practices guide)" + fi + fi # Substitute {{_openspec_manifest}} using awk with a manifest temp file # (awk -v cannot handle multi-line values; use getline from a file instead) From 45e7ead9552de855b33fce5afc3bdc1c915e3782 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:27:06 -0400 Subject: [PATCH 07/20] =?UTF-8?q?Ralph=20iteration=2014:=20**Implement=20b?= =?UTF-8?q?ash=20unit=20tests=20for=20ralphify=5Finit=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Implement bash unit tests for ralphify_init, check_ralphified, and guard** --- scripts/ralph-run.sh | 2 +- tests/helpers/test-functions.sh | 155 +++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 2 deletions(-) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 44ea100..7852e9c 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -1243,7 +1243,7 @@ WARNING_BOX echo " [C] Continue without init" >&2 echo " [Q] Quit" >&2 printf "Enter choice: " >&2 - read -r choice <&2 + read -r choice case "$choice" in [Aa]) diff --git a/tests/helpers/test-functions.sh b/tests/helpers/test-functions.sh index 1592c5f..af94fe6 100644 --- a/tests/helpers/test-functions.sh +++ b/tests/helpers/test-functions.sh @@ -56,7 +56,7 @@ get_realpath() { fi } -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}" LOCAL_NODE_BIN="$SCRIPT_DIR/../../node_modules/.bin" MINI_RALPH_CLI="$SCRIPT_DIR/../../scripts/mini-ralph-cli.js" @@ -997,6 +997,159 @@ execute_ralph_loop() { +ralphify_init() { + local bp_file="$SCRIPT_DIR/../OPENSPEC-RALPH-BP.md" + local config_file="openspec/config.yaml" + local agents_file="AGENTS.md" + + if ! git rev-parse --git-dir > /dev/null 2>&1; then + log_error "Not a git repository. Please run: git init" + return 1 + fi + + if [[ ! -d "openspec" ]]; then + log_error "openspec/ directory not found. Please run: openspec init" + return 1 + fi + + if [[ ! -f "$bp_file" ]]; then + log_error "OPENSPEC-RALPH-BP.md not found at $bp_file" + log_error "Package installation may be incomplete. Run: npm install" + return 1 + fi + + if ! grep -q "Ralph Wiggum" "$config_file" 2>/dev/null; then + cat >> "$config_file" << 'RALPH_CONFIG' + +# --- Ralph Wiggum --- +# This project uses the Ralph Wiggum method for iterative development. +# See OPENSPEC-RALPH-BP.md for the detailed authoring guide shipped with spec-and-loop. +context: | + This project follows the Ralph Wiggum method for task authoring. + Read OPENSPEC-RALPH-BP.md before generating OpenSpec artifacts. + Verify proposals against the Ralph checklist before approval. +rules: + proposal: + - Include explicit scope, non-goals, and first-rollout boundaries + - Resolve all policy decisions before implementation tasks + tasks: + - Use the task template from OPENSPEC-RALPH-BP.md + - Each task has one dominant outcome and one verification cluster + - Include explicit stop-and-hand-off conditions + design: + - Do not leave core policy choices unresolved + - Specify algorithms, config shapes, and failure semantics +RALPH_CONFIG + log_verbose "Updated $config_file with Ralph Wiggum rules" + else + log_verbose "Ralph Wiggum rules already present in $config_file" + fi + + if ! grep -q "Ralph Wiggum Compliance" "$agents_file" 2>/dev/null; then + cat >> "$agents_file" << 'RALPH_AGENTS' + +## Ralph Wiggum Compliance + +This project follows the Ralph Wiggum method for iterative OpenSpec development. + +Before generating any OpenSpec artifacts, you MUST: +- Read `OPENSPEC-RALPH-BP.md` in the project root +- Verify proposals against the Ralph authoring checklist +- Ensure tasks use the task template with objective done-when conditions +- Include explicit stop-and-hand-off conditions in every task +RALPH_AGENTS + log_verbose "Updated $agents_file with Ralph Wiggum compliance section" + else + log_verbose "Ralph Wiggum compliance section already present in $agents_file" + fi + + log_info "Project ralphified successfully. Proposals will now follow Ralph Wiggum best practices." + return 0 +} + +check_ralphified() { + local config_file="openspec/config.yaml" + local agents_file="AGENTS.md" + + if [[ ! -f "$config_file" ]]; then + return 1 + fi + + if [[ ! -f "$agents_file" ]]; then + return 1 + fi + + if ! grep -q "Ralph Wiggum" "$config_file" 2>/dev/null; then + return 1 + fi + + if ! grep -q "Ralph Wiggum Compliance" "$agents_file" 2>/dev/null; then + return 1 + fi + + return 0 +} + +show_ralphify_warning() { + local change_name="$1" + + cat >&2 << 'WARNING_BOX' +┌─────────────────────────────────────────────────────────────────────┐ +│ │ +│ WARNING: Project not configured for Ralph Wiggum best practices │ +│ │ +│ This project has not been ralphified. Proposals and artifacts │ +│ may not follow Ralph Wiggum conventions. │ +│ │ +│ It is recommended to run: ralph-run init │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +WARNING_BOX + + while true; do + echo "" >&2 + echo "Choose an option:" >&2 + echo " [A] Run ralphify init and redo the proposal, then continue" >&2 + echo " [C] Continue without init" >&2 + echo " [Q] Quit" >&2 + printf "Enter choice: " >&2 + read -r choice + + case "$choice" in + [Aa]) + log_info "Running ralphify init..." + if ! ralphify_init; then + log_error "ralphify init failed. Aborting." + exit 1 + fi + + local change_dir="openspec/changes/$change_name" + if [[ -f "$change_dir/proposal.md" ]]; then + rm "$change_dir/proposal.md" + log_info "Deleted proposal.md for redo" + fi + + log_info "Invoking opencode to regenerate proposal..." + opencode -p "/opsx-continue $change_name" || true + + log_info "Returning to loop execution..." + return 0 + ;; + [Cc]) + log_info "Continuing without Ralph Wiggum configuration." + return 0 + ;; + [Qq]) + log_info "Exiting." + exit 0 + ;; + *) + echo "Invalid choice '$choice'. Please enter A, C, or Q." >&2 + ;; + esac + done +} + # Initialize OS detection (only when run directly, not when sourced) if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then detect_os From 5a803a9a824b932392dbde1eeed2d57b8873716f Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:29:23 -0400 Subject: [PATCH 08/20] =?UTF-8?q?Ralph=20iteration=2015:=20**Update=20READ?= =?UTF-8?q?ME.md=20with=20ralphify=20workflow=20and=20init=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Update README.md with ralphify workflow and init command** --- README.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 48106a6..69866f1 100644 --- a/README.md +++ b/README.md @@ -47,16 +47,19 @@ brew install anomalyco/tap/opencode # 1. Initialize OpenSpec in your project openspec init -# 2. Create a new change +# 2. Ralphify your project (enables Ralph-friendly artifact generation) +ralph-run init + +# 3. Create a new change openspec new change add-user-auth -# 3. Review and complete the OpenSpec artifacts +# 4. Review and complete the OpenSpec artifacts # (openspec/changes/add-user-auth/proposal.md) # (openspec/changes/add-user-auth/design.md) # (openspec/changes/add-user-auth/specs/*/spec.md) # (openspec/changes/add-user-auth/tasks.md) -# 4. Run the ralph loop (executes tasks with opencode) +# 5. Run the ralph loop (executes tasks with opencode) ralph-run --change add-user-auth ``` @@ -144,6 +147,8 @@ For complete installation instructions, see [QUICKSTART.md](./QUICKSTART.md). ### Ralph Loop Commands +- `ralph-run init` - Configure project for Ralph-friendly artifact generation (run once after `openspec init`) + ``` ralph-run [OPTIONS] @@ -158,6 +163,9 @@ OBSERVABILITY AND CONTROL: --status Print the current loop status dashboard and exit --add-context Add pending context to inject into the next iteration and exit --clear-context Clear any pending context and exit + +SUBCOMMANDS: + init Configure project for Ralph-friendly artifact generation ``` ## How It Works @@ -232,13 +240,16 @@ cd my-web-app git init openspec init -# 2. Create a new change +# 2. Ralphify your project +ralph-run init + +# 3. Create a new change openspec new change user-auth -# 3. Complete OpenSpec artifacts manually or use opencode skills +# 4. Complete OpenSpec artifacts manually or use opencode skills # (review and fill in proposal.md, design.md, specs/*/spec.md, tasks.md) -# 4. Execute with Ralph +# 5. Execute with Ralph ralph-run --change user-auth # Output: From 4384c0883039f54068764c61a82614b521074fb1 Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:31:50 -0400 Subject: [PATCH 09/20] =?UTF-8?q?Ralph=20iteration=2016:=20**Update=20QUIC?= =?UTF-8?q?KSTART.md=20with=20ralphify=20workflow=20and=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] **Update QUICKSTART.md with ralphify workflow and init command** --- QUICKSTART.md | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/QUICKSTART.md b/QUICKSTART.md index b883cf7..ae9f188 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -53,16 +53,19 @@ git init # 2. Initialize OpenSpec openspec init -# 3. Create a new change +# 3. Ralphify your project (enables Ralph-friendly artifact generation) +ralph-run init + +# 4. Create a new change openspec new change add-hello-world -# 4. Review and complete the OpenSpec artifacts +# 5. Review and complete the OpenSpec artifacts # (openspec/changes/add-hello-world/proposal.md) # (openspec/changes/add-hello-world/design.md) # (openspec/changes/add-hello-world/specs/*/spec.md) # (openspec/changes/add-hello-world/tasks.md) -# 5. Run the ralph loop (executes tasks with opencode) +# 6. Run the ralph loop (executes tasks with opencode) ralph-run --change add-hello-world ``` @@ -145,6 +148,7 @@ openspec schemas # List available workflow schemas ### Ralph Loop Commands ```bash +ralph-run init # Configure project for Ralph-friendly artifact generation ralph-run # Auto-detect most recent change and run ralph-run --change # Run for specific change ralph-run --verbose # Run with debug output @@ -165,31 +169,34 @@ cd my-web-app git init openspec init -# 2. Create a feature +# 2. Ralphify your project +ralph-run init + +# 3. Create a feature openspec new change user-authentication -# 3. Go through the workflow +# 4. Go through the workflow # - Create proposal: Why add auth? # - Create specs: Login flow, password reset, OAuth # - Create design: Use JWT, store hashed passwords # - Create tasks: 15 checkboxes for implementation -# 4. Execute the implementation +# 5. Execute the implementation ralph-run --change user-authentication -# 5. Watch the magic happen! +# 6. Watch the magic happen! # [INFO] Found 15 tasks to execute # [INFO] Executing task 1/15: Create User model # [INFO] Executing task 2/15: Implement password hashing # ... -# 6. Add context mid-run if needed (from another terminal) +# 7. Add context mid-run if needed (from another terminal) ralph-run --add-context "Prefer bcrypt over argon2 for password hashing" -# 7. Check status +# 8. Check status ralph-run --status -# 8. Verify the implementation +# 9. Verify the implementation git log --oneline # 15 commits, one per task git diff HEAD~15 # See full implementation ``` @@ -412,6 +419,21 @@ nvm use 24 # Or install from https://nodejs.org ``` +### "Project not ralphified" + +**Problem:** Running `ralph-run --change ` shows a warning that the project is not ralphified, or artifacts are missing Ralph-friendly structure. + +**Solution:** +```bash +# Run ralphify init to configure the project (run once after openspec init) +ralph-run init + +# Verify ralphification succeeded +ralph-run --status +``` + +This sets up Ralph-friendly rules in `openspec/config.yaml` and `AGENTS.md`. Run it once per project after `openspec init`. + ### "npm: command not found" **Problem:** npm is not installed or not in PATH From 98ad2c0edc5429114fec17a80862fc65b5b0b94a Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:51:06 -0400 Subject: [PATCH 10/20] Ralph iteration 17: **Run final integrated quality gates** Tasks completed: - [x] **Run final integrated quality gates** --- scripts/ralph-run.sh | 29 +++++++++------ tests/helpers/test-functions.sh | 37 +++++++++---------- tests/unit/bash/test-get-realpath.bats | 4 +- .../unit/bash/test-symlink-architecture.bats | 3 +- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/scripts/ralph-run.sh b/scripts/ralph-run.sh index 7852e9c..85e15d1 100755 --- a/scripts/ralph-run.sh +++ b/scripts/ralph-run.sh @@ -498,17 +498,19 @@ parse_tasks() { TASKS=() TASK_IDS=() - local line_number=0 - while IFS= read -r line; do - ((line_number++)) || true - - if [[ "$line" == "- [ ]"* ]]; then - local task_desc="${line#- \[ \] }" - TASKS+=("$task_desc") - TASK_IDS+=("$line_number") - log_verbose "Found incomplete task (line $line_number): $task_desc" - fi - done < "$tasks_file" + if [[ -f "$tasks_file" ]]; then + local line_number=0 + while IFS= read -r line; do + ((line_number++)) || true + + if [[ "$line" == "- [ ]"* ]]; then + local task_desc="${line#- \[ \] }" + TASKS+=("$task_desc") + TASK_IDS+=("$line_number") + log_verbose "Found incomplete task (line $line_number): $task_desc" + fi + done < "$tasks_file" + fi log_verbose "Found ${#TASKS[@]} incomplete tasks" } @@ -1243,7 +1245,10 @@ WARNING_BOX echo " [C] Continue without init" >&2 echo " [Q] Quit" >&2 printf "Enter choice: " >&2 - read -r choice + if ! read -r choice; then + log_info "Non-interactive environment detected. Continuing without Ralph Wiggum configuration." + return 0 + fi case "$choice" in [Aa]) diff --git a/tests/helpers/test-functions.sh b/tests/helpers/test-functions.sh index af94fe6..292f14d 100644 --- a/tests/helpers/test-functions.sh +++ b/tests/helpers/test-functions.sh @@ -393,13 +393,7 @@ generate_prd() { prd_content+="$OPENSPEC_DESIGN"$'\n'$'\n' # Add current task context for Ralph to use in commits - local task_context - task_context=$(get_current_task_context "$change_dir") - - if [[ -n "$task_context" ]]; then - prd_content+="## Current Task Context"$'\n'$'\n' - prd_content+="$task_context"$'\n'$'\n' - fi + # (Removed: task context is now provided via {{task_context}} template variable only) echo "$prd_content" } @@ -434,17 +428,19 @@ parse_tasks() { TASKS=() TASK_IDS=() - local line_number=0 - while IFS= read -r line; do - ((line_number++)) || true - - if [[ "$line" == "- [ ]"* ]]; then - local task_desc="${line#- \[ \] }" - TASKS+=("$task_desc") - TASK_IDS+=("$line_number") - log_verbose "Found incomplete task (line $line_number): $task_desc" - fi - done < "$tasks_file" + if [[ -f "$tasks_file" ]]; then + local line_number=0 + while IFS= read -r line; do + ((line_number++)) || true + + if [[ "$line" == "- [ ]"* ]]; then + local task_desc="${line#- \[ \] }" + TASKS+=("$task_desc") + TASK_IDS+=("$line_number") + log_verbose "Found incomplete task (line $line_number): $task_desc" + fi + done < "$tasks_file" + fi log_verbose "Found ${#TASKS[@]} incomplete tasks" } @@ -1113,7 +1109,10 @@ WARNING_BOX echo " [C] Continue without init" >&2 echo " [Q] Quit" >&2 printf "Enter choice: " >&2 - read -r choice + if ! read -r choice; then + log_info "Non-interactive environment detected. Continuing without Ralph Wiggum configuration." + return 0 + fi case "$choice" in [Aa]) diff --git a/tests/unit/bash/test-get-realpath.bats b/tests/unit/bash/test-get-realpath.bats index 1f7ef4e..19d4e9b 100644 --- a/tests/unit/bash/test-get-realpath.bats +++ b/tests/unit/bash/test-get-realpath.bats @@ -154,9 +154,9 @@ teardown() { } @test "get_realpath: returns empty string for non-existent path" { - # Mock realpath + # Mock command to report realpath as available command() { - [[ "$1" == "realpath" ]] && return 0 + [[ "${1:-}" == "-v" ]] && return 0 return 1 } diff --git a/tests/unit/bash/test-symlink-architecture.bats b/tests/unit/bash/test-symlink-architecture.bats index fb86765..8c703df 100644 --- a/tests/unit/bash/test-symlink-architecture.bats +++ b/tests/unit/bash/test-symlink-architecture.bats @@ -171,8 +171,7 @@ teardown() { if [[ "$os" == "Linux" ]]; then target_inode=$(stat -c %i "$change_dir/tasks.md") - # Follow the symlink to get the target inode - symlink_inode=$(stat -c %i "$ralph_dir/ralph-tasks.md") + symlink_inode=$(stat -L -c %i "$ralph_dir/ralph-tasks.md") elif [[ "$os" == "macOS" ]]; then target_inode=$(stat -f %i "$change_dir/tasks.md") # On macOS, stat -f %i returns the symlink's own inode; use -L to follow the symlink From 586cdc119ba13bda33b0b499c310aba5c44e242d Mon Sep 17 00:00:00 2001 From: Nixon Cheaz <6854716+ncheaz@users.noreply.github.com> Date: Sat, 25 Apr 2026 18:04:50 -0400 Subject: [PATCH 11/20] =?UTF-8?q?Ralph=20iteration=201:=20Remove=20`.ralph?= =?UTF-8?q?/PRD.md`=20line=20from=20manifest=20in=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks completed: - [x] 1.1 Remove `.ralph/PRD.md` line from manifest in `create_prompt_template()` (`ralph-run.sh:841`) --- .cursor/commands/opsx-apply.md | 4 +- .cursor/commands/opsx-bulk-archive.md | 2 +- .cursor/commands/opsx-explore.md | 24 +- .cursor/commands/opsx-onboard.md | 48 +- .cursor/commands/opsx-verify.md | 6 +- .cursor/skills/openspec-apply-change/SKILL.md | 6 +- .../skills/openspec-archive-change/SKILL.md | 2 +- .../openspec-bulk-archive-change/SKILL.md | 4 +- .../skills/openspec-continue-change/SKILL.md | 2 +- .cursor/skills/openspec-explore/SKILL.md | 28 +- .cursor/skills/openspec-ff-change/SKILL.md | 2 +- .cursor/skills/openspec-new-change/SKILL.md | 2 +- .cursor/skills/openspec-onboard/SKILL.md | 50 +- .cursor/skills/openspec-sync-specs/SKILL.md | 2 +- .../skills/openspec-verify-change/SKILL.md | 8 +- .github/prompts/opsx-apply.prompt.md | 149 +++++ .github/prompts/opsx-archive.prompt.md | 154 +++++ .github/prompts/opsx-bulk-archive.prompt.md | 239 ++++++++ .github/prompts/opsx-continue.prompt.md | 111 ++++ .github/prompts/opsx-explore.prompt.md | 170 ++++++ .../prompts/opsx-ff.prompt.md | 22 +- .github/prompts/opsx-new.prompt.md | 66 +++ .github/prompts/opsx-onboard.prompt.md | 547 +++++++++++++++++ .github/prompts/opsx-sync.prompt.md | 131 +++++ .github/prompts/opsx-verify.prompt.md | 161 +++++ .github/skills/openspec-apply-change/SKILL.md | 156 +++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .../openspec-bulk-archive-change/SKILL.md | 246 ++++++++ .../skills/openspec-continue-change/SKILL.md | 118 ++++ .github/skills/openspec-explore/SKILL.md | 288 +++++++++ .../skills/openspec-ff-change}/SKILL.md | 23 +- .github/skills/openspec-new-change/SKILL.md | 74 +++ .github/skills/openspec-onboard/SKILL.md | 554 ++++++++++++++++++ .github/skills/openspec-sync-specs/SKILL.md | 138 +++++ .../skills/openspec-verify-change/SKILL.md | 168 ++++++ .../skills/openspec-apply-change/SKILL.md | 156 +++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .../openspec-bulk-archive-change/SKILL.md | 246 ++++++++ .../skills/openspec-continue-change/SKILL.md | 118 ++++ .kilocode/skills/openspec-explore/SKILL.md | 288 +++++++++ .kilocode/skills/openspec-ff-change/SKILL.md | 101 ++++ .kilocode/skills/openspec-new-change/SKILL.md | 74 +++ .kilocode/skills/openspec-onboard/SKILL.md | 554 ++++++++++++++++++ .kilocode/skills/openspec-sync-specs/SKILL.md | 138 +++++ .../skills/openspec-verify-change/SKILL.md | 168 ++++++ .kilocode/workflows/opsx-apply.md | 145 +++++ .kilocode/workflows/opsx-archive.md | 150 +++++ .kilocode/workflows/opsx-bulk-archive.md | 235 ++++++++ .kilocode/workflows/opsx-continue.md | 107 ++++ .kilocode/workflows/opsx-explore.md | 166 ++++++ .kilocode/workflows/opsx-ff.md | 90 +++ .kilocode/workflows/opsx-new.md | 62 ++ .kilocode/workflows/opsx-onboard.md | 543 +++++++++++++++++ .kilocode/workflows/opsx-sync.md | 127 ++++ .kilocode/workflows/opsx-verify.md | 157 +++++ .../skills/openspec-apply-change/SKILL.md | 6 +- .../skills/openspec-archive-change/SKILL.md | 2 +- .../openspec-bulk-archive-change/SKILL.md | 4 +- .../skills/openspec-continue-change/SKILL.md | 2 +- .opencode/skills/openspec-explore/SKILL.md | 28 +- .opencode/skills/openspec-ff-change/SKILL.md | 2 +- .opencode/skills/openspec-new-change/SKILL.md | 2 +- .opencode/skills/openspec-onboard/SKILL.md | 50 +- .opencode/skills/openspec-sync-specs/SKILL.md | 2 +- .../skills/openspec-verify-change/SKILL.md | 8 +- AGENTS.md | 3 + package-lock.json | 176 ++++-- package.json | 8 +- scripts/ralph-run.sh | 109 +++- tests/unit/bash/test-check-ralphified.bats | 124 ++++ .../bash/test-create-prompt-template.bats | 8 +- tests/unit/bash/test-ralphify-guard.bats | 169 ++++++ tests/unit/bash/test-ralphify-init.bats | 323 ++++++++++ 73 files changed, 8316 insertions(+), 268 deletions(-) create mode 100644 .github/prompts/opsx-apply.prompt.md create mode 100644 .github/prompts/opsx-archive.prompt.md create mode 100644 .github/prompts/opsx-bulk-archive.prompt.md create mode 100644 .github/prompts/opsx-continue.prompt.md create mode 100644 .github/prompts/opsx-explore.prompt.md rename .cursor/commands/opsx-propose.md => .github/prompts/opsx-ff.prompt.md (86%) create mode 100644 .github/prompts/opsx-new.prompt.md create mode 100644 .github/prompts/opsx-onboard.prompt.md create mode 100644 .github/prompts/opsx-sync.prompt.md create mode 100644 .github/prompts/opsx-verify.prompt.md create mode 100644 .github/skills/openspec-apply-change/SKILL.md create mode 100644 .github/skills/openspec-archive-change/SKILL.md create mode 100644 .github/skills/openspec-bulk-archive-change/SKILL.md create mode 100644 .github/skills/openspec-continue-change/SKILL.md create mode 100644 .github/skills/openspec-explore/SKILL.md rename {.cursor/skills/openspec-propose => .github/skills/openspec-ff-change}/SKILL.md (85%) create mode 100644 .github/skills/openspec-new-change/SKILL.md create mode 100644 .github/skills/openspec-onboard/SKILL.md create mode 100644 .github/skills/openspec-sync-specs/SKILL.md create mode 100644 .github/skills/openspec-verify-change/SKILL.md create mode 100644 .kilocode/skills/openspec-apply-change/SKILL.md create mode 100644 .kilocode/skills/openspec-archive-change/SKILL.md create mode 100644 .kilocode/skills/openspec-bulk-archive-change/SKILL.md create mode 100644 .kilocode/skills/openspec-continue-change/SKILL.md create mode 100644 .kilocode/skills/openspec-explore/SKILL.md create mode 100644 .kilocode/skills/openspec-ff-change/SKILL.md create mode 100644 .kilocode/skills/openspec-new-change/SKILL.md create mode 100644 .kilocode/skills/openspec-onboard/SKILL.md create mode 100644 .kilocode/skills/openspec-sync-specs/SKILL.md create mode 100644 .kilocode/skills/openspec-verify-change/SKILL.md create mode 100644 .kilocode/workflows/opsx-apply.md create mode 100644 .kilocode/workflows/opsx-archive.md create mode 100644 .kilocode/workflows/opsx-bulk-archive.md create mode 100644 .kilocode/workflows/opsx-continue.md create mode 100644 .kilocode/workflows/opsx-explore.md create mode 100644 .kilocode/workflows/opsx-ff.md create mode 100644 .kilocode/workflows/opsx-new.md create mode 100644 .kilocode/workflows/opsx-onboard.md create mode 100644 .kilocode/workflows/opsx-sync.md create mode 100644 .kilocode/workflows/opsx-verify.md create mode 100644 AGENTS.md create mode 100644 tests/unit/bash/test-check-ralphified.bats create mode 100644 tests/unit/bash/test-ralphify-guard.bats create mode 100644 tests/unit/bash/test-ralphify-init.bats diff --git a/.cursor/commands/opsx-apply.md b/.cursor/commands/opsx-apply.md index a6b077b..fcfa6c9 100644 --- a/.cursor/commands/opsx-apply.md +++ b/.cursor/commands/opsx-apply.md @@ -35,7 +35,7 @@ Implement tasks from an OpenSpec change. ``` This returns: - - Context file paths (varies by schema) + - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema) - Progress (total, complete, remaining) - Task list with status - Dynamic instruction based on current state @@ -47,7 +47,7 @@ Implement tasks from an OpenSpec change. 4. **Read context files** - Read the files listed in `contextFiles` from the apply instructions output. + Read every file path listed under `contextFiles` from the apply instructions output. The files depend on the schema being used: - **spec-driven**: proposal, specs, design, tasks - Other schemas: follow the contextFiles from CLI output diff --git a/.cursor/commands/opsx-bulk-archive.md b/.cursor/commands/opsx-bulk-archive.md index cae62d1..00efc2e 100644 --- a/.cursor/commands/opsx-bulk-archive.md +++ b/.cursor/commands/opsx-bulk-archive.md @@ -80,7 +80,7 @@ This skill allows you to batch-archive changes, handling spec conflicts intellig Display a table summarizing all changes: ``` - | Change | Artifacts | Tasks | Specs | Conflicts | Status | + | Change | Artifacts | Tasks | Specs | Conflicts | Status | |---------------------|-----------|-------|---------|-----------|--------| | schema-management | Done | 5/5 | 2 delta | None | Ready | | project-config | Done | 3/3 | 1 delta | None | Ready | diff --git a/.cursor/commands/opsx-explore.md b/.cursor/commands/opsx-explore.md index a1fbd17..f1aceec 100644 --- a/.cursor/commands/opsx-explore.md +++ b/.cursor/commands/opsx-explore.md @@ -59,10 +59,10 @@ Depending on what the user brings, you might: │ Use ASCII diagrams liberally │ ├─────────────────────────────────────────┤ │ │ -│ ┌────────┐ ┌────────┐ │ -│ │ State │────────▶│ State │ │ -│ │ A │ │ B │ │ -│ └────────┘ └────────┘ │ +│ ┌────────┐ ┌────────┐ │ +│ │ State │────────▶│ State │ │ +│ │ A │ │ B │ │ +│ └────────┘ └────────┘ │ │ │ │ System diagrams, state machines, │ │ data flows, architecture sketches, │ @@ -119,14 +119,14 @@ If the user mentions a change or you detect one is relevant: 3. **Offer to capture when decisions are made** - | Insight Type | Where to Capture | - |--------------|------------------| - | New requirement discovered | `specs//spec.md` | - | Requirement changed | `specs//spec.md` | - | Design decision made | `design.md` | - | Scope changed | `proposal.md` | - | New work identified | `tasks.md` | - | Assumption invalidated | Relevant artifact | + | Insight Type | Where to Capture | + |----------------------------|--------------------------------| + | New requirement discovered | `specs//spec.md` | + | Requirement changed | `specs//spec.md` | + | Design decision made | `design.md` | + | Scope changed | `proposal.md` | + | New work identified | `tasks.md` | + | Assumption invalidated | Relevant artifact | Example offers: - "That's a design decision. Capture it in design.md?" diff --git a/.cursor/commands/opsx-onboard.md b/.cursor/commands/opsx-onboard.md index 301b4d7..381a680 100644 --- a/.cursor/commands/opsx-onboard.md +++ b/.cursor/commands/opsx-onboard.md @@ -464,21 +464,21 @@ This same rhythm works for any size change—a small fix or a major feature. **Core workflow:** -| Command | What it does | -|---------|--------------| -| `/opsx:propose` | Create a change and generate all artifacts | -| `/opsx:explore` | Think through problems before/during work | -| `/opsx:apply` | Implement tasks from a change | -| `/opsx:archive` | Archive a completed change | + | Command | What it does | + |-------------------|--------------------------------------------| + | `/opsx:propose` | Create a change and generate all artifacts | + | `/opsx:explore` | Think through problems before/during work | + | `/opsx:apply` | Implement tasks from a change | + | `/opsx:archive` | Archive a completed change | **Additional commands:** -| Command | What it does | -|---------|--------------| -| `/opsx:new` | Start a new change, step through artifacts one at a time | -| `/opsx:continue` | Continue working on an existing change | -| `/opsx:ff` | Fast-forward: create all artifacts at once | -| `/opsx:verify` | Verify implementation matches artifacts | + | Command | What it does | + |--------------------|----------------------------------------------------------| + | `/opsx:new` | Start a new change, step through artifacts one at a time | + | `/opsx:continue` | Continue working on an existing change | + | `/opsx:ff` | Fast-forward: create all artifacts at once | + | `/opsx:verify` | Verify implementation matches artifacts | --- @@ -516,21 +516,21 @@ If the user says they just want to see the commands or skip the tutorial: **Core workflow:** -| Command | What it does | -|---------|--------------| -| `/opsx:propose ` | Create a change and generate all artifacts | -| `/opsx:explore` | Think through problems (no code changes) | -| `/opsx:apply ` | Implement tasks | -| `/opsx:archive ` | Archive when done | + | Command | What it does | + |--------------------------|--------------------------------------------| + | `/opsx:propose ` | Create a change and generate all artifacts | + | `/opsx:explore` | Think through problems (no code changes) | + | `/opsx:apply ` | Implement tasks | + | `/opsx:archive ` | Archive when done | **Additional commands:** -| Command | What it does | -|---------|--------------| -| `/opsx:new ` | Start a new change, step by step | -| `/opsx:continue ` | Continue an existing change | -| `/opsx:ff ` | Fast-forward: all artifacts at once | -| `/opsx:verify ` | Verify implementation | + | Command | What it does | + |---------------------------|-------------------------------------| + | `/opsx:new ` | Start a new change, step by step | + | `/opsx:continue ` | Continue an existing change | + | `/opsx:ff ` | Fast-forward: all artifacts at once | + | `/opsx:verify ` | Verify implementation | Try `/opsx:propose` to start your first change. ``` diff --git a/.cursor/commands/opsx-verify.md b/.cursor/commands/opsx-verify.md index b87c212..eca3900 100644 --- a/.cursor/commands/opsx-verify.md +++ b/.cursor/commands/opsx-verify.md @@ -35,7 +35,7 @@ Verify that an implementation matches the change artifacts (specs, tasks, design openspec instructions apply --change "" --json ``` - This returns the change directory and context files. Read all available artifacts from `contextFiles`. + This returns the change directory and `contextFiles` (artifact ID -> array of concrete file paths). Read all available artifacts from `contextFiles`. 4. **Initialize verification report structure** @@ -49,7 +49,7 @@ Verify that an implementation matches the change artifacts (specs, tasks, design 5. **Verify Completeness** **Task Completion**: - - If tasks.md exists in contextFiles, read it + - If `contextFiles.tasks` exists, read every file path in it - Parse checkboxes: `- [ ]` (incomplete) vs `- [x]` (complete) - Count complete vs total tasks - If incomplete tasks exist: @@ -88,7 +88,7 @@ Verify that an implementation matches the change artifacts (specs, tasks, design 7. **Verify Coherence** **Design Adherence**: - - If design.md exists in contextFiles: + - If `contextFiles.design` exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions - If contradiction detected: diff --git a/.cursor/skills/openspec-apply-change/SKILL.md b/.cursor/skills/openspec-apply-change/SKILL.md index d474dc1..70fbdb8 100644 --- a/.cursor/skills/openspec-apply-change/SKILL.md +++ b/.cursor/skills/openspec-apply-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Implement tasks from an OpenSpec change. @@ -39,7 +39,7 @@ Implement tasks from an OpenSpec change. ``` This returns: - - Context file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs) + - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs) - Progress (total, complete, remaining) - Task list with status - Dynamic instruction based on current state @@ -51,7 +51,7 @@ Implement tasks from an OpenSpec change. 4. **Read context files** - Read the files listed in `contextFiles` from the apply instructions output. + Read every file path listed under `contextFiles` from the apply instructions output. The files depend on the schema being used: - **spec-driven**: proposal, specs, design, tasks - Other schemas: follow the contextFiles from CLI output diff --git a/.cursor/skills/openspec-archive-change/SKILL.md b/.cursor/skills/openspec-archive-change/SKILL.md index 9b1f851..12e2f70 100644 --- a/.cursor/skills/openspec-archive-change/SKILL.md +++ b/.cursor/skills/openspec-archive-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Archive a completed change in the experimental workflow. diff --git a/.cursor/skills/openspec-bulk-archive-change/SKILL.md b/.cursor/skills/openspec-bulk-archive-change/SKILL.md index d2f199a..5be81af 100644 --- a/.cursor/skills/openspec-bulk-archive-change/SKILL.md +++ b/.cursor/skills/openspec-bulk-archive-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Archive multiple completed changes in a single operation. @@ -84,7 +84,7 @@ This skill allows you to batch-archive changes, handling spec conflicts intellig Display a table summarizing all changes: ``` - | Change | Artifacts | Tasks | Specs | Conflicts | Status | + | Change | Artifacts | Tasks | Specs | Conflicts | Status | |---------------------|-----------|-------|---------|-----------|--------| | schema-management | Done | 5/5 | 2 delta | None | Ready | | project-config | Done | 3/3 | 1 delta | None | Ready | diff --git a/.cursor/skills/openspec-continue-change/SKILL.md b/.cursor/skills/openspec-continue-change/SKILL.md index a2856f0..4f2c3dc 100644 --- a/.cursor/skills/openspec-continue-change/SKILL.md +++ b/.cursor/skills/openspec-continue-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Continue working on a change by creating the next artifact. diff --git a/.cursor/skills/openspec-explore/SKILL.md b/.cursor/skills/openspec-explore/SKILL.md index ffa10ca..6858d3f 100644 --- a/.cursor/skills/openspec-explore/SKILL.md +++ b/.cursor/skills/openspec-explore/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes. @@ -56,10 +56,10 @@ Depending on what the user brings, you might: │ Use ASCII diagrams liberally │ ├─────────────────────────────────────────┤ │ │ -│ ┌────────┐ ┌────────┐ │ -│ │ State │────────▶│ State │ │ -│ │ A │ │ B │ │ -│ └────────┘ └────────┘ │ +│ ┌────────┐ ┌────────┐ │ +│ │ State │────────▶│ State │ │ +│ │ A │ │ B │ │ +│ └────────┘ └────────┘ │ │ │ │ System diagrams, state machines, │ │ data flows, architecture sketches, │ @@ -114,14 +114,14 @@ If the user mentions a change or you detect one is relevant: 3. **Offer to capture when decisions are made** - | Insight Type | Where to Capture | - |--------------|------------------| - | New requirement discovered | `specs//spec.md` | - | Requirement changed | `specs//spec.md` | - | Design decision made | `design.md` | - | Scope changed | `proposal.md` | - | New work identified | `tasks.md` | - | Assumption invalidated | Relevant artifact | + | Insight Type | Where to Capture | + |----------------------------|--------------------------------| + | New requirement discovered | `specs//spec.md` | + | Requirement changed | `specs//spec.md` | + | Design decision made | `design.md` | + | Scope changed | `proposal.md` | + | New work identified | `tasks.md` | + | Assumption invalidated | Relevant artifact | Example offers: - "That's a design decision. Capture it in design.md?" @@ -227,7 +227,7 @@ User: A CLI tool that tracks local dev environments You: That changes everything. ┌─────────────────────────────────────────────────┐ - │ CLI TOOL DATA STORAGE │ + │ CLI TOOL DATA STORAGE │ └─────────────────────────────────────────────────┘ Key constraints: diff --git a/.cursor/skills/openspec-ff-change/SKILL.md b/.cursor/skills/openspec-ff-change/SKILL.md index d5f1204..43f2632 100644 --- a/.cursor/skills/openspec-ff-change/SKILL.md +++ b/.cursor/skills/openspec-ff-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Fast-forward through artifact creation - generate everything needed to start implementation in one go. diff --git a/.cursor/skills/openspec-new-change/SKILL.md b/.cursor/skills/openspec-new-change/SKILL.md index 607391a..1af41c7 100644 --- a/.cursor/skills/openspec-new-change/SKILL.md +++ b/.cursor/skills/openspec-new-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Start a new change using the experimental artifact-driven approach. diff --git a/.cursor/skills/openspec-onboard/SKILL.md b/.cursor/skills/openspec-onboard/SKILL.md index 9076b5d..b6c734d 100644 --- a/.cursor/skills/openspec-onboard/SKILL.md +++ b/.cursor/skills/openspec-onboard/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Guide the user through their first complete OpenSpec workflow cycle. This is a teaching experience—you'll do real work in their codebase while explaining each step. @@ -468,21 +468,21 @@ This same rhythm works for any size change—a small fix or a major feature. **Core workflow:** -| Command | What it does | -|---------|--------------| -| `/opsx:propose` | Create a change and generate all artifacts | -| `/opsx:explore` | Think through problems before/during work | -| `/opsx:apply` | Implement tasks from a change | -| `/opsx:archive` | Archive a completed change | + | Command | What it does | + |-------------------|--------------------------------------------| + | `/opsx:propose` | Create a change and generate all artifacts | + | `/opsx:explore` | Think through problems before/during work | + | `/opsx:apply` | Implement tasks from a change | + | `/opsx:archive` | Archive a completed change | **Additional commands:** -| Command | What it does | -|---------|--------------| -| `/opsx:new` | Start a new change, step through artifacts one at a time | -| `/opsx:continue` | Continue working on an existing change | -| `/opsx:ff` | Fast-forward: create all artifacts at once | -| `/opsx:verify` | Verify implementation matches artifacts | + | Command | What it does | + |--------------------|----------------------------------------------------------| + | `/opsx:new` | Start a new change, step through artifacts one at a time | + | `/opsx:continue` | Continue working on an existing change | + | `/opsx:ff` | Fast-forward: create all artifacts at once | + | `/opsx:verify` | Verify implementation matches artifacts | --- @@ -520,21 +520,21 @@ If the user says they just want to see the commands or skip the tutorial: **Core workflow:** -| Command | What it does | -|---------|--------------| -| `/opsx:propose ` | Create a change and generate all artifacts | -| `/opsx:explore` | Think through problems (no code changes) | -| `/opsx:apply ` | Implement tasks | -| `/opsx:archive ` | Archive when done | + | Command | What it does | + |--------------------------|--------------------------------------------| + | `/opsx:propose ` | Create a change and generate all artifacts | + | `/opsx:explore` | Think through problems (no code changes) | + | `/opsx:apply ` | Implement tasks | + | `/opsx:archive ` | Archive when done | **Additional commands:** -| Command | What it does | -|---------|--------------| -| `/opsx:new ` | Start a new change, step by step | -| `/opsx:continue ` | Continue an existing change | -| `/opsx:ff ` | Fast-forward: all artifacts at once | -| `/opsx:verify ` | Verify implementation | + | Command | What it does | + |---------------------------|-------------------------------------| + | `/opsx:new ` | Start a new change, step by step | + | `/opsx:continue ` | Continue an existing change | + | `/opsx:ff ` | Fast-forward: all artifacts at once | + | `/opsx:verify ` | Verify implementation | Try `/opsx:propose` to start your first change. ``` diff --git a/.cursor/skills/openspec-sync-specs/SKILL.md b/.cursor/skills/openspec-sync-specs/SKILL.md index 353bfac..f2ed9ec 100644 --- a/.cursor/skills/openspec-sync-specs/SKILL.md +++ b/.cursor/skills/openspec-sync-specs/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Sync delta specs from a change to main specs. diff --git a/.cursor/skills/openspec-verify-change/SKILL.md b/.cursor/skills/openspec-verify-change/SKILL.md index 744a088..00d0532 100644 --- a/.cursor/skills/openspec-verify-change/SKILL.md +++ b/.cursor/skills/openspec-verify-change/SKILL.md @@ -6,7 +6,7 @@ compatibility: Requires openspec CLI. metadata: author: openspec version: "1.0" - generatedBy: "1.2.0" + generatedBy: "1.3.1" --- Verify that an implementation matches the change artifacts (specs, tasks, design). @@ -39,7 +39,7 @@ Verify that an implementation matches the change artifacts (specs, tasks, design openspec instructions apply --change "" --json ``` - This returns the change directory and context files. Read all available artifacts from `contextFiles`. + This returns the change directory and `contextFiles` (artifact ID -> array of concrete file paths). Read all available artifacts from `contextFiles`. 4. **Initialize verification report structure** @@ -53,7 +53,7 @@ Verify that an implementation matches the change artifacts (specs, tasks, design 5. **Verify Completeness** **Task Completion**: - - If tasks.md exists in contextFiles, read it + - If `contextFiles.tasks` exists, read every file path in it - Parse checkboxes: `- [ ]` (incomplete) vs `- [x]` (complete) - Count complete vs total tasks - If incomplete tasks exist: @@ -92,7 +92,7 @@ Verify that an implementation matches the change artifacts (specs, tasks, design 7. **Verify Coherence** **Design Adherence**: - - If design.md exists in contextFiles: + - If `contextFiles.design` exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions - If contradiction detected: diff --git a/.github/prompts/opsx-apply.prompt.md b/.github/prompts/opsx-apply.prompt.md new file mode 100644 index 0000000..e23ec64 --- /dev/null +++ b/.github/prompts/opsx-apply.prompt.md @@ -0,0 +1,149 @@ +--- +description: Implement tasks from an OpenSpec change (Experimental) +--- + +Implement tasks from an OpenSpec change. + +**Input**: Optionally specify a change name (e.g., `/opsx:apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. + +**Steps** + +1. **Select the change** + + If a name is provided, use it. Otherwise: + - Infer from conversation context if the user mentioned a change + - Auto-select if only one active change exists + - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select + + Always announce: "Using change: " and how to override (e.g., `/opsx:apply `). + +2. **Check status to understand the schema** + ```bash + openspec status --change "" --json + ``` + Parse the JSON to understand: + - `schemaName`: The workflow being used (e.g., "spec-driven") + - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) + +3. **Get apply instructions** + + ```bash + openspec instructions apply --change "" --json + ``` + + This returns: + - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema) + - Progress (total, complete, remaining) + - Task list with status + - Dynamic instruction based on current state + + **Handle states:** + - If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx:continue` + - If `state: "all_done"`: congratulate, suggest archive + - Otherwise: proceed to implementation + +4. **Read context files** + + Read every file path listed under `contextFiles` from the apply instructions output. + The files depend on the schema being used: + - **spec-driven**: proposal, specs, design, tasks + - Other schemas: follow the contextFiles from CLI output + +5. **Show current progress** + + Display: + - Schema being used + - Progress: "N/M tasks complete" + - Remaining tasks overview + - Dynamic instruction from CLI + +6. **Implement tasks (loop until done or blocked)** + + For each pending task: + - Show which task is being worked on + - Make the code changes required + - Keep changes minimal and focused + - Mark task complete in the tasks file: `- [ ]` → `- [x]` + - Continue to next task + + **Pause if:** + - Task is unclear → ask for clarification + - Implementation reveals a design issue → suggest updating artifacts + - Error or blocker encountered → report and wait for guidance + - User interrupts + +7. **On completion or pause, show status** + + Display: + - Tasks completed this session + - Overall progress: "N/M tasks complete" + - If all done: suggest archive + - If paused: explain why and wait for guidance + +**Output During Implementation** + +``` +## Implementing: (schema: ) + +Working on task 3/7: +[...implementation happening...] +✓ Task complete + +Working on task 4/7: +[...implementation happening...] +✓ Task complete +``` + +**Output On Completion** + +``` +## Implementation Complete + +**Change:** +**Schema:** +**Progress:** 7/7 tasks complete ✓ + +### Completed This Session +- [x] Task 1 +- [x] Task 2 +... + +All tasks complete! You can archive this change with `/opsx:archive`. +``` + +**Output On Pause (Issue Encountered)** + +``` +## Implementation Paused + +**Change:** +**Schema:** +**Progress:** 4/7 tasks complete + +### Issue Encountered + + +**Options:** +1.