Vercel Logo

Publish a draft

After independent verification, the factory may open a draft pull request. Policy still denies ready pull requests, and the factory has no merge capability.

if (input?.draft === true) return "not-applicable";
return { reason: "The factory may create draft pull requests only.", type: "denied" };

A draft carries the real diff and decision evidence. Final authority remains with a person.

Ship Proof, Keep Merge Authority

Deploy the factory and allow it to publish independently verified draft pull requests only.

Hands-on Exercise 5.2

Create agent/lib/github/approval.ts:

agent/lib/github/approval.ts
import type { ApprovalContext, ApprovalStatus } from "eve/tools";
 
export function createPullRequestPolicy(ctx: ApprovalContext): ApprovalStatus {
  const input = ctx.toolInput as { draft?: unknown } | undefined;
  if (input?.draft === true) {
    return "not-applicable";
  }
  return {
    reason: "The factory may create draft pull requests only.",
    type: "denied",
  };
}

Create agent/extensions/github.ts and include only the repository tools the orchestrator needs. Connect createPullRequest to the policy:

agent/extensions/github.ts
import githubExtension from "@github-tools/eve-extension";
import { factoryRepo } from "../lib/config.js";
import { createPullRequestPolicy } from "../lib/github/approval.js";
import { GITHUB_CONNECTOR } from "../lib/github/credentials.js";
 
export default githubExtension({
  connector: GITHUB_CONNECTOR,
  context: factoryRepo,
  include: [
    "getRepository",
    "getIssueContext",
    "listIssueComments",
    "listBranches",
    "getPullRequestContext",
    "listPullRequestFiles",
    "createPullRequest",
  ],
  requireApproval: {
    createPullRequest: createPullRequestPolicy,
  },
});

factoryRepo supplies { owner, repo }; GITHUB_CONNECTOR names the attached connector. The include list is the complete GitHub capability set, with no stored personal token.

Add two tests at agent/lib/github/approval.test.ts: drafts return "not-applicable", while a ready pull request returns { type: "denied" }.

Finish agent/instructions.md with the pull request body requirements. Include the problem statement, acceptance criteria with verification results, commands run, risks, deviations, and a link to the issue. Call github__createPullRequest with draft: true only after the Verifier approves.

The application was linked, given AI Gateway credentials, and attached to GitHub in Lesson 3.1. Deploy that linked application now:

pnpm exec eve deploy

Use the same personal GitHub repository configured for the sandboxes. The deployment preserves the channel, tools, subagents, approval policy, and durable session behavior.

Try It

Run the local policy checks before testing the deployed factory:

pnpm test agent/lib/github/approval.test.ts
pnpm typecheck
pnpm exec eve info

Create an issue from fixtures/issues/bug-example.md, then add the factory label from an account with repository triage access or higher. Follow the run through verification. Its pull request should be a draft with evidence for every criterion.

If nothing starts, verify each connection in order:

vercel connect list
pnpm exec eve info

Confirm the connector targets /eve/v1/github, its UID matches GITHUB_CONNECTOR, the App can access the repository, and the deployment includes agent/channels/github.ts.

Attempt a ready pull request through the policy test. It must be denied. Confirm that the extension exposes no merge tool.

Review from the pull request only

Pretend the agent conversation is unavailable. Can you decide what to inspect from the issue link, diff, criteria, commands, and verification report in the draft body?

The pull request opens ready

Pass draft: true and keep the policy test. Prompt instructions alone cannot enforce a draft-only boundary.

The repository belongs to an organization

Vercel Hobby projects require the course repository under your personal GitHub account.

Commit

git add agent/extensions agent/lib/github agent/instructions.md
git commit -m "feat(factory): publish verified drafts"

Done-When

  • The GitHub extension exposes no merge capability
  • Ready pull requests fail the policy test
  • Draft creation happens only after verification approval
  • The draft body carries the specification and evidence
  • The deployed factory processes a labeled GitHub issue

The factory can now produce reviewable work while merge authority remains external. The final lesson turns failed decisions into regression evaluations.

Solution

The complete pull request policy is shown in the exercise. Its test is:

agent/lib/github/approval.test.ts
import { describe, expect, it } from "vitest";
import { createPullRequestPolicy } from "./approval.js";
 
describe("createPullRequestPolicy", () => {
  it("permits draft pull requests", () => {
    expect(createPullRequestPolicy({ toolInput: { draft: true } } as never))
      .toBe("not-applicable");
  });
 
  it("denies pull requests that are ready for review", () => {
    expect(createPullRequestPolicy({ toolInput: { draft: false } } as never))
      .toMatchObject({ type: "denied" });
  });
});

Was this helpful?

supported.