[KongchangAI]
· 4 min read· 2,279 words

Migrating AI Coding Agents: Split Proposal from Application Before Canceling Your Old Workspace

Migrating AI Coding Agents: Split Proposal from Application Before Canceling Your Old Workspace

When migrating AI coding agents, the real risk is leftover merge permissions — split proposal, approval, and apply with named owners and a fail-closed gate.

When switching from a paid AI coding workspace to a free alternative, the biggest risk isn't model quality but the automated scripts and webhooks still holding push credentials. This migration journal proposes separating proposal, approval, and apply into three governed stages: free models can generate proposals, but approvals must come from a human in an agent-proof path, and push credentials must stay in protected CI. The methodology covers scanning for merge-capable paths, implementing a fail-closed diff-hash validator, running three real historical tasks side-by-side across both platforms, and only deleting old keys after a full decision-table review.

When you're ready to cancel a paid AI coding workspace and switch to a free alternative, the most dangerous thing isn't model quality — it's the automated hook that can still execute merges. Paid products tend to treat "propose, review, apply" as a single trusted continuous action, and free alternatives don't inherit that trust. Free models can write useful patches just fine, but the executor must never hold the credentials to push them.

This migration journal offers an actionable methodology: separate the three responsibilities of proposing, approving, and applying; assign an owner to each; use a fail-closed validator as a gate; and only delete your old keys after you've validated against real tasks.

Migration Journal: Split Proposal from Application Before Canceling Your Workspace

The Real Legacy Is Merge Permission, Not Prompts

During migration, most people focus on prompts and model performance while overlooking the truly dangerous thing — the script, workflow, or webhook that still "knows how to merge." This automation previously trusted a vendor identity, a stable workspace, and a review click in the old interface.

Once you've switched, that same automation will trust any process that can drop a diff into the monitored path. If your free server can write to that path, you've effectively rebuilt the old privilege without the old review mechanism.

The author emphasizes that you're actually migrating three things, and only one of them should be moved to cheaper hosting:

  • The proposal channel can be migrated, because a draft diff isn't yet a change to the default branch.
  • The approval record should stay in the reviewer's hands — in a pull request or a protected file the model cannot edit.
  • The apply credentials should remain in protected CI or with a designated person, until you've done side-by-side comparison on real tasks.

The key advice: before changing any environment variable or webhook, write down the owner of each of these three things in your journal. A handoff with no named owners degrades into a chat log, and that chat log disappears when the paid workspace closes. You'll wish you had those names when the first bad patch lands — not in a cheerful launch announcement.

How Webhooks and Git Hooks Inherit Permissions

Webhooks are server-side HTTP callbacks triggered when specific Git events (such as push or pull request) occur — the hosting platform sends a request to a preset endpoint. Git hooks are local or server-side scripts that run automatically at lifecycle points like pre-commit or post-merge. The shared danger of both is that they're bound to paths and credentials, not to the identity of the caller. Paid AI workspaces typically scope writes via OAuth Apps or Fine-grained Tokens; canceling the subscription invalidates those tokens. But if your migration script reuses a more permissive GITHUB_TOKEN, or the webhook secret was never rotated, then any process that can send a legitimately signed request to that endpoint inherits the original push privilege. This is why the author insists that named owners must exist before any environment variable changes — once the old token is revoked and the new one is filled in, the audit chain breaks, but the permission gap may already be open.

Step 1: Inventory Every Path That Can Apply a Diff

Start from a clean checkout and search for the "verbs" that can turn generated text into a commit or deployment. Don't evaluate model quality yet — just find the side effects that might outlive your vendor relationship. Local scripts and editor tasks count too: hooks on your laptop persist after cancellation just as hosted workflows do.

Specific steps:

  1. Search for apply, merge, and push actions in your workflows and scripts. Store the file list in an "apply paths" section of your journal so later decisions are grounded in evidence rather than memory:
git grep -nE 'git apply|gh pr merge|git push|patch -p' -- .github scripts || true
  1. List every secret name the agent process might read, and bold any that can push, deploy, or modify a firewall. Secrets that only read logs can wait, but secrets that can push must be bolded in your journal. Record only names, owners, and the workflow files that reference them — never copy secret values into the journal:
git grep -nE 'GITHUB_TOKEN|DEPLOY_KEY|SSH_KEY|API_KEY' -- .github scripts .env.example || true
  1. Review recent agent run logs to confirm whether a human review signal appears before any merge event. If the log jumps directly from "diff written" to "pushed," the gate was never there.
  2. In the same note, write down both a rollback owner and a secrets owner, including how to reach them. A free server with no rollback owner cannot substitute for the paid agent your on-call team already understands. If either name is blank, stop the migration and fix the runbook first.

Step 2: Freeze a Proposal Contract the New Host Must Honor

The author defines separate contracts for "proposal" and "apply." A valid proposal must carry: a task ID, a base revision, a unified-format diff, and a risk label drawn from the team's existing list. A valid apply must reference the same task ID, the hash of that diff, and a human operator tied to the review.

The core principle is clear: the model may write the proposal, but the model may not write the approval — even if the patch looks small and obvious.

The validator should be "boring" and fail-closed whenever any required field is empty or the operator is the agent itself. The Python example validator in the article reads two JSON files, rejects model-written approvals, and only permits the apply when hashes match:


**The Security Boundary of Diff Hash Verification**

The validator uses `SHA-256` to digest the diff text. The core assumption is that the bytes the reviewer signed must be exactly the bytes that get executed. This mechanism defends against two typical attacks: "post-approval substitution" — where the agent quietly modifies the diff after approval then submits it — and "path confusion" — moving the approval file from one approved task next to a different task's proposal. But hash verification has clear blind spots: it validates byte integrity, not semantic safety. A diff with a perfect SHA-256 match can still contain logic bugs, a reversed database migration, or a missed permission check. This is the fundamental reason the author emphasizes in "Limitations That Remain After a Green Light" that executable tests must be preserved — a hash is a necessary condition, not a sufficient one. The same logic applies to locking `base_rev`: if the default branch advances during the approval window, applying the same diff to the new HEAD can produce entirely different semantic results, which is why you must snapshot it with `git rev-parse` at proposal generation time.

# Example checker. Label: unexecuted until you run it on your own files.
import hashlib, json, pathlib, sys

REQUIRED = ("task_id", "base_rev", "diff", "risk")

def proposal_digest(proposal):
    missing = [k for k in REQUIRED if not proposal.get(k)]
    if missing:
        raise SystemExit(f"proposal missing {missing}")
    if proposal.get("approved_by"):
        raise SystemExit("model must not set approved_by")
    return hashlib.sha256(proposal["diff"].encode()).hexdigest()

The author specifically notes: this is an example that you need to run and adapt on your own files — it is not a policy engine the journal claims to have already executed. The recommendation is to manufacture a deliberate mismatch as your first test — you should see the gate fail before you trust it to pass.

One commonly overlooked pitfall is storage paths. Proposals should live in a location the executor can write to; approvals should live in a path the executor cannot push to. Even if the validation function looks strict on your laptop, a loosely permissioned shared directory makes the entire split meaningless. Use code owners or a separate approvals repository, and confirm that the agent token is rejected when it attempts to write there.

Step 3: Point Only the Proposal Writer at the Free Tier

Disclosure: The original article states it was written as part of promotional content for MonkeyCode.

As the author describes it, the operator positions MonkeyCode as an open-source project offering free model access and a free server option for the "proposal writer." This writer should hold no push credentials, and you should confirm the current terms in the project documentation before use. The article also honestly notes: don't reuse token quota numbers from old chat logs, as quotas change and those numbers weren't verified when this draft was written.

There's an important distinction to internalize: availability is not the same as quality outcomes, nor is it a promise about log retention duration. The free option should be treated as a place to run the proposal writer — not as evidence that you can skip review. Your repository rules still apply on free hosting, even if it's no longer sending you an invoice.

The recommended switching cadence:

  1. Pick three tasks you've already accepted: one low-risk edit, one dependency upgrade, and one change touching auth, billing, or data migration.
  2. Save the file list, base revision, and diff hash from the paid run. Don't invent new tasks during the switching week.
  3. Run the same task through the free model, allowing the process to write only a proposal file.
  4. Compare paths and the locked base revision — not surrounding explanations. Wording can drift; scope cannot.
  5. Don't apply anything from your laptop during this period. Let CI reject tasks until a reviewer writes a matching approval.

The author offers one hard rule: a file that appears outside the saved list is a stop — even if tests on the expected files are all green. Scope creep is exactly how an unreviewed edit passes through a badge that never looked at that extra path. Also lock the base revision first (git rev-parse origin/main), because a moving default branch will make both hosts appear to be "wrong."

How Code Owners and Protected Branches Isolate Permissions

GitHub's CODEOWNERS file lets you designate mandatory reviewers for specific paths: any Pull Request touching those paths is blocked from merging by branch protection rules until the listed people have approved it. The article's suggestion to store approval files in a Code Owners–protected path leverages exactly this mechanism: even if an agent token has write access to the repository, as long as the approval path is protected by CODEOWNERS with "Require review from Code Owners" enabled, the agent cannot merge a commit containing the approval file without a human reviewer intervening. An even more complete isolation is to use a separate "approvals repository": keep the proposal repo and approval repo separate, give the agent token write access only to the proposal repo and read-only access to the approval repo, and have the executor perform cross-repo signature verification before merging. This way, even if the proposal-side host is fully compromised, the attacker cannot forge a legitimate approval record.

Step 4: Read the Decision Table Before Deleting the Paid Key

The author provides a decision table and asks you to treat it as a gate rather than a summary to skim afterward. If any cell's status is unknown, application traffic must remain on the old path.

CheckPaid Side StatusFree Side RequirementMigrate Apply?
Diff writerVendor agent identityProposal path onlyProposal only
Approval writerHuman in old UIPath agent cannot push toNo, until enforced
Base revisionWorkspace snapshotbase_rev locked and verifiedNo, if tip can drift
Push keyVendor-scoped or protected CIAbsent from free serverNo, if key is copied
Rollback ownerNamed in old runbookSame owner, updated linkNo, if name is blank
Three-task hash comparisonOften skipped beforeRecorded before switchNo, until logged in journal

Migrate the proposal writer only when both the "Diff writer" and "Push key" rows are satisfied. Migrate the apply task only when every remaining row is satisfied across all three saved tasks. The author's closing words are measured: keeping a paid key one extra week is far cheaper than reversing a merge that no reviewer ever saw.

Limitations That Remain After a Green Light

A matching hash only proves that the bytes that were approved are the bytes that were proposed. It does not prove those bytes are safe to ship. A free model can perfectly edit the expected files while breaking a caller, a migration, or a permission check you forgot to name. You must therefore keep executable tests on the tasks and maintain a trusted path until those tests also go green on the new writer.

The example validator trusts your repository permissions to protect the approval path from the agent token. If that token can push to that path, the gate is theater — and you should not migrate the apply task at all in that case.

The author also defines who this doesn't apply to: if your current agent can bypass pull requests and deploy directly to production; if no designated reviewer will read high-risk diffs; if tasks involve secrets, customer data, or undisclosed vulnerability details; or if your team still applies patches from laptops with no protected CI — none of these scenarios should rush into a switch. A cheaper bill doesn't relax the data rules you already accepted for your paid agent.

This journal ranks no products, reports no benchmarks, and gives no token prices or hardware specs. Your three real tasks are the only evidence that determines whether the apply task should migrate.

#AI coding agent migration#merge permission security#proposal approval apply separation#webhook security#CI/CD automation safety#free tier AI tools#diff hash validation#code owners protection
Share:

Related articles