Recently Written · git

deploy-handoff

Claude Code plugin: the agent drives the browser to the last deploy, billing, or pull request step. You make the final click.

git clone https://github.com/equwal/deploy-handoff

Log | Files | Refs


rules/deploy-handoff.md (9024 bytes)

1 ## MANDATORY: The word DEPLOY runs the full pipeline at max verification
2 
3 When the user's message is, or contains, the standalone word "DEPLOY" (any
4 case), treat it as one command: run the full pipeline below. Do not ask which
5 part they mean. Try each step. When a step does not apply to this project,
6 say so and move on. A step that does not apply is not a blocked step.
7 
8 1. **Verify at max rigor first.** Run the strictest check the project has:
9    formatter, linter, a strict type check, and the full test suite. Add a
10    regression test for each new behavior. Run each check as a real command
11    and show the output. A step with no command output is not done. If the
12    project has none of this tooling, say so instead of skipping silently.
13 2. **Version.** Try to set a version number for the change. Use the scheme
14    the project already has: bump the version field in `package.json`,
15    `pyproject.toml`, `Cargo.toml`, or a similar manifest. If it has no such
16    file but already uses git tags for versions, add the next tag. If neither
17    exists, say so and skip.
18 3. **Ship.** Commit the change with a self-contained message, keep secrets
19    out of the diff, and push.
20 4. **Upstream.** Try to push the change upstream. Follow "Pull requests"
21    below: if the repo is a fork, or has an `upstream` remote, and the change
22    is useful to the upstream project, open that pull request.
23 5. **Live deploy.** Try to put the change where it runs live. Do each of
24    these the project actually has:
25    - A deploy platform config (`vercel.json`, `netlify.toml`,
26      `wrangler.toml`, `fly.toml`, a GitHub Actions deploy workflow).
27    - A VPS the project deploys to: an SSH or rsync deploy script, an Ansible
28      playbook, or a Docker Compose file with a known host. Restart the
29      service after the copy.
30    - A local install or run step on this computer: a local package install,
31      a copy to a run folder, or a restart of a local daemon or service.
32    If the project has none of these, say so and skip.
33 6. **Hand off what is left.** Give the user each step that needs a live key,
34    a production flag, a domain purchase, a sign-in, or another human action.
35    Use the `deploy-handoff` skill for each one.
36 
37 Report one line per part: done, blocked, or not applicable, with the cause
38 for a blocked part.
39 
40 ## MANDATORY: Hand off human steps. Do not refuse the task.
41 
42 The `deploy-handoff` plugin is installed. Its skill shows the user a dialog with the last step of a task. The user makes the final click in the browser.
43 
44 Some steps of a deploy, publish, billing, app store, or sign-in task are for the user only. Do not refuse or stop the task because of these steps. Do all the other work. Then give each such step to the user with the `deploy-handoff` skill. Do not only tell the user in the chat.
45 
46 A handoff is the last resort. First try a command. Then try the browser. Hand off only the step that is left.
47 
48 Use the skill for these steps:
49 
50 - The final click that deploys to production, publishes a release, submits an app for review, turns on live payments, or buys a domain.
51 - A sign-in, a two-factor code, an OAuth consent, a CAPTCHA, or the acceptance of terms.
52 - The creation of an account, an API key, a webhook secret, or another secret. Tell the user where to put the secret. Never ask for the secret in the chat or in the dialog.
53 - A step that needs the explicit yes of the user, for example the switch to live payments.
54 - A deploy command that a permission check denied. Do not run the command again. If the platform has a web page for the same step, hand off that page.
55 - A question that a program asks in a terminal before it continues: an install question, the sign-in of a command line program, or a confirmation of a change that cannot be undone.
56 
57 If the step is a question in a terminal, start the program in a terminal that the user sees, stop at the question, and use the terminal handoff of the skill (`handoff.py terminal`). Do not type the answer.
58 
59 If the step has no web page and no question in a terminal, ask the user in the chat.
60 
61 To hand off:
62 
63 1. Drive the browser as far as you can with your browser tools.
64 2. Use the skill. Write the title and the steps in Simplified Technical English.
65 3. While the dialog is open, continue the other tasks. If the answer is "done", check the result. Then continue the task.
66 
67 ## More than one task: stop only the blocked task
68 
69 A request can have more than one task, for example a web deploy, a store release, and a payment setup. A task is blocked when it gets to a step that you cannot do. Examples: a sign-in, an account creation, a CAPTCHA, a permission prompt that the user denied, or an error that you cannot fix.
70 
71 A blocked task does not stop the other tasks. When a task is blocked:
72 
73 1. Stop that task, and each task that needs its result.
74 2. If the blocked step has a web page, hand it off with the skill. Run the dialog in the background.
75 3. Continue all the other tasks while the dialog is open.
76 4. When the user answers "done", check the result. Then continue the blocked task.
77 5. Put each question for the user at the end, after the other tasks are done or blocked. A question ends your turn and stops the other tasks.
78 
79 At the end, give the result of each task: done or blocked. For a blocked task, give the cause and the step that the user must do.
80 
81 If the user tells you to stop, stop all the tasks.
82 
83 ## Deploys that need no browser: run the command
84 
85 Many deploy steps need no web page. A CLI does them. Examples: `vercel deploy`, `netlify deploy`, `wrangler deploy`, `flyctl deploy`, `gh release create`, `docker push`, `git push`, `stripe` CLI commands, `gradlew bundleRelease`.
86 
87 For these steps:
88 
89 1. Run the command with your shell tool.
90 2. Let the permission prompt ask the user. The prompt is the approval. Do not hand off the step to avoid the prompt.
91 3. Some permission modes show no prompt. In these modes, ask the user in the chat before a production deploy, a release, or a live payment change.
92 4. Show the output. The output is the evidence that the step is complete.
93 5. If the user denies the command, do not run it again. Hand off the web page for the same step, or ask the user.
94 
95 Do not hand off a step that a command can do. A handoff for a command that you can run wastes the time of the user.
96 
97 Do not give the user a list of commands to copy and run. This is the same error. Work on a server through SSH is also a command: copy the build, install the package, restart the service. Run each command. Bring the user to the one step that needs a person, and stop there.
98 
99 On Windows, run `handoff.py` in Git Bash, not in Windows PowerShell 5.1. PowerShell 5.1 removes the double quotation marks in the arguments.
100 
101 ## Browser: go all the way to the last step
102 
103 Use browser automation to remove work from the user. Do not stop at the home page of a console.
104 
105 1. Open the console with your browser tools.
106 2. Click through each page: the project, the app, the release, the settings tab, the correct panel.
107 3. Fill in each field that holds no secret. Upload the build. Select the track. Type the release notes. Select the plan.
108 4. Read the page to make sure of the state before the last step.
109 5. Stop at the last step. Hand off that one click with `--no-open` and the URL of the open page.
110 
111 Hand off a shallow page only when the browser cannot go deeper, for example after a sign-in wall or a CAPTCHA. Tell the user in the chat which page stopped you.
112 
113 ## Browser profile: use the profile of the user
114 
115 The user is signed in to the consoles in one browser profile. Use this profile for each browser step.
116 
117 - Do not start a fresh browser profile unless the user asks for it in this session. A fresh profile has no sign-in. This includes `handoff.py browser --fresh`, the `browser-driver` agent, and the built-in browser of the Claude app.
118 - Drive the profile with the Claude in Chrome tools. If they are not available, hand off the page with `handoff.py open`.
119 - `handoff.py open` opens the page in the Brave profile that `brave_profile` names in `~/.config/deploy-handoff/config.toml`. Without this key, it opens the default browser.
120 
121 ## Pull requests
122 
123 Prefer a direct commit and push when the user asked for the change. It needs no click from the user.
124 
125 Open a pull request only when one of these is true:
126 
127 - The user asked for a pull request.
128 - The push failed because the branch is protected, or the repository needs a review.
129 - The repository belongs to a client, an employer, or another team.
130 - The repository is a fork, and the change is useful to the upstream project.
131 
132 Open each pull request with `handoff.py pr` from the skill. For a pull request from a fork to its upstream repository, add `--repo UPSTREAM_OWNER/NAME`. Do not create a pull request with `gh pr create`, the GitHub API, or a GitHub MCP tool.
133 
134 Never use `--no-verify`. Never push when the test suite fails.
135 
136 The handoff moves a step to the user. It does not remove a safety limit. You still never type a secret, solve a CAPTCHA, or click the final button yourself.