aitask-web-merge

Merge completed Claude Web branches to main and archive task data.

SKILL.md

GitHub

Overview

This skill runs locally after aitask-pickweb completes on Claude Code Web. It detects remote branches with completed task executions, merges code to main (excluding .aitask-data-updated/), copies the plan to aitask-data, archives the task, and cleans up.

Workflow: scan → select → pull → merge → copy plan → materialize active gates → archive → push → cleanup

Workflow

Step 1: Scan for Completed Branches

Run the helper script to detect branches with completion markers:

./.aitask-scripts/aitask_web_merge.sh --fetch

If output is NONE: Inform user "No completed Claude Web branches found." and end the workflow.

If completions found: For each COMPLETED:<branch>:<marker> line, read the full completion marker JSON:

git show origin/<branch>:.aitask-data-updated/<marker>

Parse the JSON to extract: task_id, task_file, plan_file, is_child, parent_id, issue_type, implemented_with (if present), completed_at, branch.

Build a list of candidate branches with this metadata.

Step 2: Select Branch

If only one branch found: Auto-select it and display: "Found 1 completed branch: <branch> (t<task_id>, <issue_type>, completed <completed_at>). Proceeding."

If multiple branches found: Use AskUserQuestion with pagination (3 per page + "Show more"):

  • Question: "Select a completed Claude Web branch to merge:"
  • Header: "Branch"
  • Options:
    • Each branch: label = branch name, description = "t<task_id> (<issue_type>) completed <completed_at>"
    • "Process all sequentially" (description: "Merge all completed branches one by one")

If "Process all" is selected, process each branch in sequence using Steps 3-6.

Step 3: Pull Latest Main and Merge Code

For the selected branch:

3a. Pull latest main:

git pull --ff-only

If pull fails (diverged history), use AskUserQuestion:

  • Question: "Failed to fast-forward main. Local main has diverged from remote. How to proceed?"
  • Header: "Pull"
  • Options:
    • "Pull with merge" (description: "Run git pull to merge remote changes")
    • "Abort" (description: "Stop the workflow, resolve manually") If "Pull with merge": run git pull. If that fails too, abort. If "Abort": end the workflow.

3b. Merge the web branch (excluding .aitask-data-updated/):

git merge origin/<branch> --no-ff --no-commit

If merge conflicts occur, use AskUserQuestion:

  • Question: "Merge conflicts detected. How to proceed?"
  • Header: "Conflict"
  • Options:
    • "Resolve manually" (description: "I'll resolve conflicts, then tell you to continue")
    • "Abort merge" (description: "Run git merge --abort and skip this branch") If "Abort merge": run git merge --abort and skip to the next branch (or end workflow). If "Resolve manually": wait for user to resolve, then continue.

3c. Remove .aitask-data-updated/ from the merge:

git rm -rf .aitask-data-updated/ 2>/dev/null || true

3d. Commit the clean merge:

Derive a description from the task filename (strip t<N>_ prefix and .md suffix, replace underscores with spaces).

This is the one commit here that cannot name its paths: it concludes the git merge above, and git refuses a partial commit during a merge (fatal: cannot do a partial commit during a merge). It takes the merge's index by construction, which is what a merge commit is. So look before committing: git status should show the merged files and nothing a concurrent session staged, because main is shared by every session in this checkout.

<!-- unscoped-commit-ok: concludes a git merge; git refuses a partial commit during a merge -->
git commit -m "<issue_type>: <description> (t<task_id>)"

Step 4: Copy Plan to aitask-data

4a. Read the plan from the remote branch:

git show origin/<branch>:.aitask-data-updated/plan_t<task_id>.md

4b. Determine the plan file path:

Derive the plan filename from the task filename in the completion marker:

  • Take the task file basename (e.g., t227_2_create_aitaskwebmerge_skill.md)
  • Replace the leading t with p (e.g., p227_2_create_aitaskwebmerge_skill.md)

Determine the target directory:

  • Parent task (task_id has no underscore): aiplans/
  • Child task (task_id like 227_2): aiplans/p<parent>/ (e.g., aiplans/p227/)
mkdir -p <target_directory>

4c. Write the plan file to the target path using the Write tool.

4d. Commit the plan to aitask-data:

./.aitask-scripts/aitask_task_commit.sh -m "ait: Add web-completed plan for t<task_id>" <plan_file_path>

<plan_file_path> is required (it resolves under aiplans/); parse the output per the outcome contract in .claude/skills/ait-git/SKILL.md.

Step 5: Materialize Active Gates, Apply Agent Attribution, and Archive Task

Materialize the active-gates tuple (before attribution/archival): Execute the Active-Gates Materialization Procedure (see materialize-gates.md). It validates the marker's profile / profile_filename provenance, runs the aitask_web_merge.sh materialize helper, and defines the status handling — on WEBMAT_INVALID / WEBMAT_FAIL it stops before archival (Retry / Abort this branch). Continue below only when it returns with a continue outcome.

If implemented_with is present in the completion marker JSON:

./.aitask-scripts/aitask_update.sh --batch <task_id> --implemented-with "<implemented_with>" --silent

Run the archive script:

./.aitask-scripts/aitask_archive.sh <task_id>

Gate-guard backstop (handle BEFORE parsing success output): if the archive script exits non-zero and prints GATE_PENDING:<csv>, the archival did not happen — do NOT treat it as success. Surface the pending gates: a reviewer satisfies them (ait gate pass <task_id> <gate> for human gates, ait gates run <task_id> for machine gates), then re-runs aitask-web-merge to complete the archival. Never self-signal a human gate.

Parse structured output and handle each line:

  • ISSUE:<task_num>:<issue_url> — Execute the Issue Update Procedure below for this task
  • PARENT_ISSUE:<task_num>:<issue_url> — Execute the Issue Update Procedure for the parent task
  • PARENT_ARCHIVED:<path> — Inform user: "All child tasks complete! Parent task also archived."
  • COMMITTED:<hash> — Note the commit hash
  • ARCHIVED_TASK:<path> / ARCHIVED_PLAN:<path> — Informational, display to user

Step 6: Push and Cleanup

6a. Push main:

git push

6b. Push aitask-data:

./ait git push

6c. Delete the remote branch:

git push origin --delete <branch>

6d. Inform user: "Branch <branch> merged, task t<task_id> archived, remote branch deleted."

6e. Process next branch (if applicable):

If multiple branches were detected in Step 1 and "Process all" was selected (or more branches remain), loop back to Step 3 for the next branch.

Otherwise, if other unprocessed branches remain, use AskUserQuestion:

  • Question: "Merge complete. There are <N> more completed branches. Process the next one?"
  • Header: "Continue"
  • Options:
    • "Yes, process next" (description: "Continue with the next completed branch")
    • "Done for now" (description: "Stop processing branches")

Step 7: Satisfaction Feedback

Execute the Satisfaction Feedback Procedure (see .claude/skills/task-workflow/satisfaction-feedback.md) with skill_name = "web-merge".


Issue Update Procedure

When a task or parent task has a linked issue (from archive script output):

Use AskUserQuestion:

  • Question: "Task t<N> has a linked issue: <issue_url>. Update/close it?"
  • Header: "Issue"
  • Options:
    • "Close with notes" (description: "Post implementation notes + commits as comment and close")
    • "Comment only" (description: "Post implementation notes but leave open")
    • "Close silently" (description: "Close without posting a comment")
    • "Skip" (description: "Don't touch the issue")

If "Close with notes":

./.aitask-scripts/aitask_issue_update.sh --close <task_num>

If "Comment only":

./.aitask-scripts/aitask_issue_update.sh <task_num>

If "Close silently":

./.aitask-scripts/aitask_issue_update.sh --close --no-comment <task_num>

If "Skip": do nothing.


Notes

  • This skill is interactive (uses AskUserQuestion) — designed for local execution, not Claude Web
  • The helper script aitask_web_merge.sh handles branch detection and the materialize provenance-validation mode; this SKILL.md handles merge/archive orchestration
  • .aitask-data-updated/ is intentionally NOT gitignored — it's committed on the web branch and explicitly removed during merge
  • The --no-ff --no-commit merge approach avoids --amend while keeping the merge commit clean
  • aitask_archive.sh handles all archival mechanics (metadata update, file moves, lock release, parent auto-archival, git commit)
  • Plan filename derivation: replace leading t with p in the task filename
  • For the web-side workflow that produces the branches this skill processes, see aitask-pickweb