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.