agentsclimarketplace

Dev cycle

Skill mataeil/OODA-loop/skills/dev-cycle

Autonomous operations layer for Claude Code — opens small reviewable PRs for your live side project and re-orients from which ones you merge or reject. HALT file + hard cost cap; you stay in command.

Install
npx -y skills add mataeil/OODA-loop --skill dev-cycle

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Full implementation cycle pipeline. Takes the highest-RICE action from the action queue and implements it through a structured test → implement → verify workflow. Primary skill for the implementation domain — invoked by evolve when implementation is selected.

SKILL.md

21.4 KB, as published. Nobody here has run it

dev-cycle: Full Implementation Cycle Pipeline

The "builder" of the harness. Takes the highest-priority action from the action queue, implements it in a dedicated branch, verifies it passes tests, and creates a Draft PR for human review.

dev-cycle is the primary skill for the implementation domain. When evolve's Orient step selects implementation as the winning domain, it calls dev-cycle. All changes go through branch + PR — dev-cycle never commits directly to main.

  • Creates Draft PRs by default — human review is mandatory for implementation
  • Creates a ready (non-draft) PR ONLY when the change is auto-merge-eligible (see "Auto-merge eligibility" below) AND the operator has opted in via config.safety.enable_auto_merge. Default behavior is Draft / human merge.
  • NEVER uses git add -A — only explicit file staging to prevent secret leaks
  • evolve (4-C) is the final merge authority — it re-checks every gate before any auto-merge; dev-cycle only chooses draft vs ready.

Safety Rules

  1. HALT file — Mandatory first check. If present, print reason and stop.
  2. Level gate — Requires progressive_complexity >= 3 or direct user invocation. Below Level 3, exit cleanly.
  3. PR size limits — Respect config.safety.max_files_per_pr and config.safety.max_lines_per_pr. Exceeding either triggers a partial PR.
  4. Protected paths — Any change touching config.safety.protected_paths forces Risk Tier 3 (already enforced — Draft only).
  5. Explicit staginggit add {file} per file. git add -A is forbidden.
  6. Test retry cap — Maximum 3 fix attempts after a test failure. Beyond that, mark action as "blocked" and exit.

Step 0: Safety

0-A: HALT Check

if file exists at config.safety.halt_file:
  Print "[HALT] dev-cycle stopped. Reason: {file_content}"
  Print "Remove to resume: rm {config.safety.halt_file}"
  EXIT immediately.

0-B: Level Gate

Read config.json → progressive_complexity.current_level  (authoritative source)
Also check config.json → implementation.enabled
if implementation.enabled == false AND not manually invoked by user:
  Print "Implementation domain is disabled. Enable it: set implementation.enabled=true in config.json (done automatically by /ooda-config level 3)"
  EXIT cleanly (not an error).
if progressive_complexity.current_level < 3 AND not manually invoked by user:
  Print "Implementation requires Level 3. Current: {current_level}"
  EXIT cleanly (not an error).

Manual invocation means the user explicitly called /dev-cycle or /evolve in this session (as opposed to being triggered automatically by evolve on a schedule). When in doubt, treat as manual invocation and allow execution.


Step 1: Select Action from Queue

LEAP mode (v1.7.0). If evolve invoked this cycle with leap_mode=true (Step 3-K, fired by an artifact-quality plateau), do NOT pick the top-RICE feature. Instead:

  • Make a step-change on targeted_dimension (the rubric axis that has stayed weakest / below bar) — overhaul, rebuild, or refactor-for-cohesion of the core responsible for that dimension. RICE is bypassed on purpose: the whole point is to do the high-effort overhaul that RICE structurally suppresses.
  • Use config.leap.max_lines (default 1500) as the size budget for Step 3, instead of config.safety.max_lines_per_pr — a re-founding of the core is legitimately larger than a feature.
  • The verification gate for a leap is the artifact critique (evolve 5-G / 4-C2): the targeted dimension must rise by config.leap.min_dimension_delta or the change is reverted. The unit test still runs (information) but a unit-test failure alone does not block a leap (a restructured module may legitimately break a smoke test that mocked its old shape).
  • Title the branch/PR leap: overhaul {targeted_dimension} so it is legible as a step-change, not a feature. Then skip the RICE selection below and go straight to Step 2 with this overhaul as the selected action. FEATURE cycles (the default) proceed with RICE selection:

Read agent/state/evolve/action_queue.json.

Find the top pending item by highest effective_rice (after decay adjustment):

data = read action_queue.json as JSON object
if data is not a valid object:
  Print "Action queue is empty or malformed. Nothing to implement."
  EXIT cleanly.

# The canonical format uses {pending:[], in_progress:[], completed:[]}
# Read from data.pending (preferred). Fallback: if data.actions exists, filter
# items with status=="pending". Fallback: if data is a plain array, filter by status.
candidates = data.pending   # or fallback as described above

if candidates is empty or not a list:
  Print "No pending actions. Nothing to implement."
  EXIT cleanly.

# Sort by effective_rice. If effective_rice is missing, fall back to rice_score.
for item in candidates:
  if item.effective_rice is undefined:
    item.effective_rice = item.rice_score * (1.0 - (item.decay_applied or 0.0))
selected = max(candidates, key=lambda x: x.effective_rice)

if selected.effective_rice <= 0:
  Print "Top candidate RICE score is {selected.effective_rice} (≤ 0). Skipping."
  EXIT cleanly.

Print selected action details:

Selected action: {selected.title}
  RICE score  : {selected.effective_rice}
  Source      : {selected.source_domain}
  Related     : {selected.related_files}

Update the action's status to "in_progress" in action_queue.json and write the file before proceeding. If the file write fails, abort and print the error.


Step 2: Create Branch

Generate a URL-safe slug from the action title:

  1. Lowercase the title.
  2. Replace spaces and underscores with hyphens.
  3. Strip all characters except [a-z0-9-].
  4. Collapse consecutive hyphens into one and trim leading/trailing hyphens.
  5. If the slug is empty after stripping (e.g., non-ASCII title like Korean), use the action ID as the slug instead (e.g., action-001). If the action ID is also empty, generate a random 8-char hex string.
  6. Truncate to 40 characters (cut at a hyphen boundary if possible).

Get today's date in YYYYMMDD format.

git checkout -b auto/dev-cycle/{date}-{action-title-slug}

If the branch already exists (e.g., retry or duplicate title), append -2, -3, etc., up to -9. If all suffixes are taken, abort with an error.

Print:

Branch: auto/dev-cycle/{date}-{action-title-slug}

Step 3: Implementation

Read context files before writing any code:

  1. If CLAUDE.md exists at the project root, read it for project conventions.
  2. For each path in selected.related_files:
    • If the file exists, read it to understand the affected code.
    • If it does not exist, print "WARN: related file not found: {path} — skipping" and continue.
    • If related_files is empty or not set, print "INFO: No related files listed — proceeding with action title and source report only.".
  3. Read selected.source_domain report (if referenced) to understand the motivation behind this action.

Step 3-PRE: Research grounding (v1.11.0 — the anti-maze step)

Why this exists. The f1 dogfood proved the loop can "iterate without improving" — a maze/local-optimum — when generation is anchored to the model's own priors instead of to external ground truth. The fix (AlphaCodium arXiv:2401.08500, which raised pass@5 19%→44% with a structured pre-generation stage; AutoCodeRover; Simon Willison's "concrete examples beat abstract requirements"): ground every non-trivial change in an external reference BEFORE writing code. This is Boyd's Observe extended to the world's knowledge, not just local state.

For any leap / quality-improving / "make it better" action (skip for a trivial mechanical edit), BEFORE writing code:

  1. Resolve a reference. Read config.references (and agent/state/research/* if present — a researched, cited playbook). Pick the reference target for this technique/domain (e.g. a named real-product level, a reference implementation URL, or a specific playbook move with its concrete API/parameters).
  2. Fetch the concrete block. WebFetch / curl the specific reference snippet (the 30–50 lines that matter — the exact API calls, parameter values, order of operations), not the whole repo. If a research playbook already contains the cited concrete spec, use that.
  3. Derive acceptance criteria from the reference: "the implementation MUST (a) call X with params Y, (b) produce effect Z visible at camera/probe C, (c) not break the gate." Record them in the cycle's outcome as reference_block + acceptance_criteria.
  4. Only then generate — implement the cited technique, adapting names to the real code. The PR/outcome records WHICH reference grounded it (grounded_in).

A leap with no grounded_in reference is a red flag for the maze: prefer researching a concrete approach over reaching for the model's first idea.

Analyze what needs to change based on the action title, source report, and the resolved reference block, then implement the changes (write and/or edit files).

Protected paths enforcement:

Before writing any file, check against config.safety.protected_paths. This prevents dev-cycle from modifying safety-critical files that could compromise the framework's integrity (self-modification prevention).

protected = config.safety.protected_paths    -- e.g., ["agent/safety/*", "skills/evolve/*", "agent/contracts/*"]

before writing or editing any file:
  for each pattern in protected:
    if file path matches glob pattern:
      Print "BLOCKED: {file} matches protected path '{pattern}'. Skipping."
      Print "Protected paths cannot be modified by dev-cycle, even at Level 3."
      Add to PR body notes: "⚠ Protected path {file} was NOT modified (blocked by safety policy)."
      Set protected_blocked = true   -- forces Draft / Risk Tier 3 below (#35)
      DO NOT write/edit this file — continue to next file.

If ALL planned files are protected, mark the action as "blocked" with memo "All target files are protected paths" and EXIT cleanly.

If protected_blocked is true (some — not all — target files were protected and skipped), the PR is never auto-merge-eligible even if the remaining diff is small and green: a partial change with safety-critical files silently dropped may be incomplete or incoherent, so a human must review it (#35).

Size limit enforcement:

Track changes as you write. After each file edit, run git diff --stat on the working tree to get authoritative counts (do not estimate):

files_changed = 0
lines_changed = 0  # counted as (additions + deletions) from git diff --numstat

Before writing each file:

if files_changed >= config.safety.max_files_per_pr:
  Print "PR size limit reached ({max_files_per_pr} files). Creating partial PR."
  Print "Remaining work noted in action-queue memos."
  Add memo to action-queue: "Partial implementation — {files_changed} files changed."
  GOTO Step 4 (verify what was done so far)

if lines_changed + estimated_lines_for_this_file > config.safety.max_lines_per_pr:
  Print "PR line limit reached ({max_lines_per_pr} lines). Creating partial PR."
  GOTO Step 4

When partial: create a NEW pending action for the unfinished scope (same source_domain, title "{original title} (remainder)", rice_score inherited) and note the split in the original action's memos field. The original action then proceeds to "proposed" like any other PR — the remainder is independently selectable next cycle and cannot be silently lost with the original stuck in_progress.


Step 4: Verify

Gate integrity (v1.10.1 — earned by the f1 probe). A static check is necessary but NOT sufficient, and a sub-agent's self-reported gate result is not trustworthy — the orchestrator must verify from facts. Two real misses the f1 overnight run surfaced, BOTH caught only by loading the artifact in its real runtime, never by the unit gate:

  1. node --check exits 0 on a same-scope const REDECLARATION that the browser ES-module parser rejects — the game wouldn't boot, yet the cycle's node --check + smoke gate "passed". For an ES-module/browser artifact, also do a module-load check (import the changed modules in their module system, e.g. node --input-type=module -e 'import("./src/x.js")', or load the page) — that catches what node --check cannot.
  2. A cumulative visual regression (over-exposed-to-white frame) passed every unit gate; only a rendered critique caught it. Rule: for rich-runtime artifacts (browser/UI/graphics/game), the verification MUST load the artifact the way its runtime does (module-load + render/screenshot critique, i.e. evolve Step 5-G), and evolve re-checks the gate from recorded facts — it does NOT take the build skill's word for "tests passed".

If config.test_command is not configured or is empty:

Print "No test_command configured. Skipping tests."
test_status = "skipped"
GOTO Step 5

If configured, run tests with timeout enforcement:

timeout {config.test_timeout_seconds or 300}s {config.test_command}

If the test command exceeds the timeout, treat as failure:

if exit_code == 124 (timeout):
  Print "ERROR: Test command timed out after {timeout}s. Treating as failure."
  test_output = "Test timeout after {timeout}s"

Track attempts:

attempt = 1
max_attempts = 3
timeout = config.test_timeout_seconds or 300

while attempt <= max_attempts:
  run test_command with timeout
  if exit_code == 0:
    test_status = "passed"
    break
  else:
    Print "Tests failed (attempt {attempt}/{max_attempts})."
    if attempt < max_attempts:
      Print "Attempting fix..."
      targeted_fix(test_output):
        1. Parse test runner output for the first failing test name and assertion message.
        2. Read the source file containing the failing assertion.
        3. Apply a single-location edit (≤ 15 lines) that addresses the assertion.
        4. Do NOT modify test files — only fix production code.
        5. If the failure is an import/module error, fix the import only.
    attempt += 1

if test_status != "passed" after 3 attempts:
  Print "[BLOCKED] Tests failed after 3 attempts. Action marked as blocked."
  Print "Review test output above and fix manually."
  Set action status to "blocked" and MOVE it to completed[] in action_queue.json
  (pending[] holds only workable items; evolve's 6-C6 hygiene sweep enforces the
   same rule — a blocked item must never sit in pending/in_progress forever)
  git stash  (preserve work without committing)
  git checkout main   (never leave the session on the dead feature branch —
                       the next evolve cycle's git operations assume main)
  EXIT with non-zero status.

When fixing between attempts: make targeted changes only — address the specific failing assertion or import error. Do not rewrite large sections.


Step 5: Create PR

Stage only the files that were explicitly changed in Step 3 and any files edited during test-fix retries in Step 4. Maintain a cumulative changed_files list across both steps.

Never use git add -A or git add ..

# Verify each file exists before staging (skip deleted files with a warning)
for file in changed_files:
  if file exists on disk:
    git add {file}
  else:
    Print "WARN: {file} no longer exists — skipping stage"
git commit -m "{selected.title}"
git push origin HEAD

If git push fails:

if error contains "conflict" or "rejected" or "non-fast-forward":
  Print "ERROR: merge conflict detected — {error}"
  Print "Resolve manually, then: git push origin {branch_name}"
  Update action status to "blocked" with memo "merge conflict with main"
else:
  Print "ERROR: git push failed — {error}"
  Print "Push manually with: git push origin {branch_name}"
  Record push error in action-queue memos.
EXIT with non-zero status.

Auto-merge eligibility (compute before creating the PR). The PR is auto-merge-eligible iff ALL of these hold:

config.safety.enable_auto_merge == true            -- opt-in, default false
AND config.progressive_complexity.current_level >= 3
AND no changed file matches config.safety.protected_paths
AND protected_blocked == false                     -- no protected file was skipped (#35)
AND changed_files_count <= config.safety.auto_merge_max_files   -- default 5
AND changed_lines_count <= config.safety.auto_merge_max_lines   -- default 100
AND test_status == "passed"                        -- the CANONICAL Step-4 value;
                                                   -- "skipped" (no test_command)
                                                   -- is NOT eligible — auto-merge
                                                   -- requires actually-green tests

If NOT eligible (the default), create the PR as Draft. If eligible, create it ready (omit --draft) and stamp auto_merge_eligible=true in the meta comment so evolve 4-C can recognize it — evolve still independently re-checks every gate before merging (defense in depth).

Create the PR (--draft UNLESS auto-merge-eligible):

gh pr create \
  --title "{selected.title}" \
  $([ "$auto_merge_eligible" = true ] || echo --draft) \
  --body "$(cat <<'EOF'
<!-- ooda:meta source_domain={selected.source_domain} rice={selected.effective_rice} action_id={selected.id} auto_merge_eligible={true|false} protected_blocked={true|false} -->

## Source
- **Domain**: {selected.source_domain}
- **RICE Score**: {selected.effective_rice}
- **Action ID**: {selected.id}

## Changes
| File | Description |
|------|-------------|
| `{file1}` | {one-line description} |

## Test Results
- **Status**: {test_status}
- **Command**: `{config.test_command}`
- **Attempts**: {attempt}/{max_attempts}
- **Output** (last run): `{last 5 lines of test output or "tests skipped"}`

## Notes
{any partial PR notes, size limit warnings, or protected-path flags}

---
Generated by OODA-loop dev-cycle v1.0.0
EOF
)"

(--draft is added by the conditional on the gh pr create line above — present unless the change is auto-merge-eligible.)

If gh is not available:

Print "gh (GitHub CLI) not found. PR creation skipped."
Print "Push the branch and create a PR manually:"
Print "  git push origin {branch_name}"
Print "  gh pr create --draft --title \"{selected.title}\""
pr_number = null

Update action_queue.json:

{
  "status": "proposed",
  "pr_number": {number or null},
  "pr_url": "{url or null}",
  "proposed_at": "{ISO 8601}"
}

Step 6: Report

Print the final summary:

dev-cycle complete — {ISO timestamp}
Action  : {selected.title} (RICE: {selected.effective_rice})
Branch  : auto/dev-cycle/{slug}
PR      : #{pr_number} ({Draft|ready})  |  {pr_url}
Files   : {files_changed} changed
Lines   : {lines_changed} changed
Tests   : {test_status}
Status  : proposed
pr_created : {true|false}

pr_created is a REQUIRED report variable (true iff a PR was actually opened this run) — it is what evolve's 4-B evaluates for this skill's chain trigger (pr_created == true). Report variables are the evaluation source for skills whose contract output file (here action_queue.json) doesn't carry the condition fields at top level.

If PR was not created (gh unavailable):

PR      : not created — push branch and create manually

Graceful Degradation

ScenarioBehavior
HALT file presentPrint reason, exit immediately
Level < 3, not manualPrint level message, exit cleanly
action_queue.json missingPrint "Action queue not found at agent/state/evolve/action_queue.json", exit cleanly
No pending actionsPrint "No pending actions", exit cleanly
Branch already existsAppend suffix (-2, -3), continue
PR size limit hitCreate partial PR, note remaining scope in action memos
Tests fail after 3 triesMark action "blocked", stash changes, exit non-zero
git push failsRecord error in memos, print manual instructions, exit non-zero
gh not installedSkip PR creation, print manual instructions, exit 0
test_command not configuredSkip tests, record "skipped", continue to PR
related_files missing/emptyProceed with action title and source report only
Protected path changedAlready in Draft mode — note in PR body as protected-path change
Merge conflict on pushAbort push, mark action "blocked" with memo "merge conflict with main", stash changes, exit non-zero
action_queue.json malformedPrint parse error, exit cleanly
Branch suffix exhausted (-9)Print error, mark action "blocked", exit non-zero

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.