Skip to content

Workspace git: rebase, reset, force-push, and a composite "bring this PR up to date" ability #410

@chubes4

Description

@chubes4

Problem

DMC's workspace-git abilities cover the happy path of an agent shipping a fresh branch: status, log, diff, pull, add, commit, push. None of them help an agent manage its own pull request backlog when reality moves faster than the agent.

Concrete failure pattern (observed today in chubes4/world-of-wordpress):

  1. Cycle 1 opens PR A touching files X, Y.
  2. Cycle 2 fires before A merges, opens PR B touching file X.
  3. Cycle 3 fires before A and B merge, sees both as open in perception, deliberately steers around X and Y to avoid conflict, ships an unrelated field note.
  4. Cycle 4 does the same. Cycle 5. Cycle 6.

Each cycle is making the correct local decision — don't conflict with your own open PRs — but the cumulative effect is the agent producing field notes during every cycle while the real work it actually wants to do is locked behind unmerged PRs that go stale.

The agent has no way to bring its own PRs home. It can detect a stale PR exists (perception surfaces open PRs). It cannot:

  • Rebase a stale day-branch onto current main so the conflict resolves.
  • Reset a branch to drop merge-conflict-inducing commits (e.g. accumulated daily-memory chore commits that always conflict with main's newer daily memory).
  • Force-push the rebased history back to the day-branch.
  • Resolve simple text conflicts inline.
  • Squash a noisy commit history into one substantive commit before the auto-merger picks it up.

A human had to do this work today by hand: rebase, cherry-pick the substantive commits, squash, force-push. That's exactly the kind of mechanical workflow an agent should own.

What this asks for

1. Three new low-level abilities

datamachine/workspace-git-rebase

Input: name (workspace handle), onto (base ref, default origin/<base-branch>), interactive (always false), strategy_option (e.g. theirs, ours, optional).

Behavior: git fetch origin && git rebase <onto> from the worktree path. If conflicts arise, return them in the output schema with file paths, conflict-marker counts, and a conflicts array. The ability does not auto-resolve; that's the agent's job using workspace_edit/workspace_write. After resolution the agent calls workspace_git_add and a new workspace_git_rebase_continue (or pass continue: true to the same ability) to resume.

Output: success, state (clean / conflicting), conflicts (array of files with marker counts), applied (commit count applied), pending (commit count still to apply).

datamachine/workspace-git-reset

Input: name, mode (one of soft, mixed, hard), target (ref or commit, default origin/<branch>).

Behavior: git reset --<mode> <target> from the worktree path. Hard reset requires an explicit allow_destructive: true flag.

Output: success, mode, previous_head, new_head, paths_affected (count, not list).

datamachine/workspace-git-push — extend existing ability

Add force_with_lease boolean parameter (default false). When true, the push uses --force-with-lease=<branch>:<expected-sha> where expected-sha is the remote tip the agent last observed. The expected SHA can be passed explicitly or computed by the ability from git ls-remote before the push.

Optional but safe: refuse force_with_lease against main regardless of any flag, the same way the existing allow_primary_mutation flag works.

2. A composite high-level ability

datamachine/workspace-pr-rebase

Input: name (worktree handle), pr (PR number or URL, optional — if omitted the ability resolves the PR from the worktree's pushed branch via the GitHub API), squash (boolean, default false), drop_paths (array of glob patterns — paths to drop during rebase rather than resolve, e.g. bundles/world-creator/memory/agent/daily/**).

Behavior:

  1. Resolve the worktree path and the PR's base branch via GitHub API.
  2. git fetch origin <base>.
  3. git rebase origin/<base> from the worktree.
  4. For each conflict file matching a drop_paths glob: resolve by taking base (git checkout --theirs <file> and git add <file>) — i.e. drop the PR's version in favor of main's. Most useful for daily-memory chore conflicts.
  5. For each remaining conflict: return as a structured conflict for the agent to resolve manually with workspace_edit/workspace_write + workspace_git_rebase (with continue: true).
  6. If squash: true after a clean rebase: git reset --soft origin/<base>, then git commit -m \"<PR title>\" using the PR's title for the message. Body inherits from the PR.
  7. git push --force-with-lease.

Output: success, state (clean / conflicting), dropped_paths (count), unresolved_conflicts (array), squashed (boolean), pushed (boolean), head_sha, pr_url.

This single ability replaces the manual workflow a human did today:

```text
git fetch origin
git checkout pr-branch
git reset --soft origin/main

(paths from drop_paths are now in working tree, agent ignores them via .gitignore-like skip)

git commit -m ""
git push --force-with-lease
```

3. Perception layer integration

The world plugin's World_Perception_Directive (and equivalent directives in other DM-hosted agents) should be able to consume the GitHub API and surface PR staleness state: for each open PR, is it ahead of base, behind base, or conflicting. Today the directive's branches section (in the world plugin) just lists open PRs without their freshness state.

That's a world-plugin concern, not a DMC concern — but DMC could expose a helper ability datamachine/workspace-pr-status (input: pr or branch, output: mergeable, behind, ahead, conflicting) that any perception layer can consume. That's a thin wrapper over gh api repos/.../pulls/<n> returning the relevant fields.

Why not just merge through the auto-merger

The world repo has an auto-merger (merge-world-creator-pr job in .github/workflows/world-creator.yml) that runs after each cycle. It uses gh pr merge and refuses to merge CONFLICTING PRs. That's correct safety behavior — the auto-merger shouldn't blindly merge conflicts.

The right answer is the agent itself resolves the conflict on its own branch, then the auto-merger merges the cleaned-up result. That's what these abilities enable.

Why a composite ability

The agent could compose git_rebase + git_add + git_reset + git_push --force-with-lease itself, but:

  1. The conflict-resolution loop is mechanical and well-defined. Agents should not burn turns on it.
  2. The composite ability can be idempotent — calling it twice on a clean PR is a no-op. Calling it twice during a conflict surfaces the same conflict.
  3. The composite ability can ship with safety rails the agent can't easily forget: never force-push to a base branch, always use --force-with-lease (never bare --force), always squash if requested.
  4. The agent's mental model becomes "bring this PR home" instead of "fetch base, rebase, resolve conflicts, squash, force-push."

Scope notes

  • DMC abilities only. No DM core changes required.
  • The new low-level abilities follow the same pattern as the existing workspace-git-* abilities — same ability category, same permission_callback, same WorkspaceTools registration shape.
  • All four new abilities should register against the same modes the existing workspace-git abilities use (chat, pipeline with requires_opt_in: true).
  • Tool registration in inc/Tools/WorkspaceTools.php follows the existing pattern.

AI assistance

  • AI assistance: Yes
  • Tool(s): Claude Code (Sonnet 4.5)
  • Used for: Diagnosed the agent's PR backlog management gap by watching the World Creator cycles repeatedly avoid conflict surfaces and produce field-note filler. Designed the four-ability addition (rebase, reset, push --force-with-lease, composite pr-rebase) plus the optional workspace-pr-status helper for perception integration. Chris specified that this is a DMC-level gap and that the agent should be able to bring its own PRs home autonomously.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions