Team handoff skill
Hand local work to a shared OpenClaw Gateway: start a worktree session there as yourself in one request, seeded with a handoff, and get the session URL back.
by openclaw·MIT license·★ 1,102 Stars on the repo·GitHub ↗
npx degit openclaw/agent-skills/skills/team-handoff#main ~/.claude/skills/team-handoffChecked ·commit main
Files of Team handoff
Show the full text113 lines
Team Handoff
Use when the user says "open a session on the team server for this", "hand this off to <team agent>", or "summarize this for a new agent and start it on <gateway>", and the target is a shared OpenClaw Gateway behind an identity-aware proxy (Cloudflare Access).
One Gateway request, as the operator's own identity. No browser automation, no SSH, no polling.
Script: scripts/team-handoff.sh
Setup (once per machine)
Operator config, outside any repo:
${XDG_CONFIG_HOME:-~/.config}/openclaw/team-handoff.envOPENCLAW_HANDOFF_URL=https://gateway.example # the shared Gateway's public origin OPENCLAW_HANDOFF_AGENT=main # default agent id on that Gateway OPENCLAW_HANDOFF_PROJECT=example-project # default projects.list id # optional: # OPENCLAW_HANDOFF_CLI=/path/to/openclaw # installed OpenClaw CLI (default: openclaw on PATH) # OPENCLAW_HANDOFF_PROFILE_DIR=~/.openclaw/profiles/team # OPENCLAW_HANDOFF_SSH_HOST=gateway-host # operator fallback only; see belowIsolated CLI profile so the local Gateway config is never touched. The script writes it on first
probewhen missing:OPENCLAW_STATE_DIRandOPENCLAW_CONFIG_PATHpoint at the profile dir, whoseopenclaw.jsonholds onlygateway.mode: "remote",gateway.remote.url, and anexecsecret provider that runscloudflared access token -app=<url>for theCf-Access-Tokenheader (gateway.remote.edgeAuth, see the OpenClaw docs page "Remote access", section "Gateway behind an identity-aware proxy"). The providercommandmust be the realcloudflaredbinary, not a symlink.The human logs in once per Access session lifetime (agents cannot):
cloudflared access login https://gateway.exampleprobeprintsokwhen the chain works.Exec provider "cloudflare-access" exited with code 1or an HTTP 302 on upgrade means the login lapsed: ask the human to run it again; do not switch to the SSH fallback on your own.
Why there is no token to mint: with gateway.auth.mode: "trusted-proxy" the
proxy authenticates the user and the Gateway maps the identity header to scopes;
first connection auto-pairs a CLI device with the proxy's deviceAutoApprove
scopes, which cover sessions.create.
Use
bash scripts/team-handoff.sh probe
bash scripts/team-handoff.sh create \
--label "Installed-package entry cap durable fix" \
--name tree-cap-fix --base origin/main \
--message-file /path/to/handoff.md
bash scripts/team-handoff.sh status <sessionKey>
bash scripts/team-handoff.sh archive <sessionKey> <sessionId>
create prints url: in the Control UI form
<origin>/chat/<agent>/<label-slug>-<session-key-uuid-without-dashes>, plus the
session key and run id. Hand the human that URL. Creation returns before the
worktree is prepared; running with worktree: null right after is normal, and
the agent's first turn starts once the checkout binds. Read status once; do not
loop.
Payload
- Branch first. Push the work, pass
--base <branch>, keep the long handoff in the branch (for example.openclaw/handoff.md); the message is then three lines: what the branch is, what to do first, what not to do. Local files are unreachable from the Gateway; commit them or summarize the numbers. - Without a branch, the whole handoff goes in
--message-file: a one-line title first (it becomes the session title and URL slug), then goal, verified facts with numbers, owner files, the agreed plan and order, proof expectations, and explicit non-goals. - Name scope boundaries when a local session keeps part of the work, so two agents do not open duplicate PRs.
Failure modes
managed worktree allocation lease .../capacity was lost: the Gateway lost its worktree capacity lease during a slow project refetch. A retry in the same session then fails withbranch already exists: openclaw/<name>because the failed attempt leaked its branch. Create a new session with a different--name; archive the dead one.chat.sendrequiresidempotencyKey;sessions.patchlifecycle changes requireexpectedSessionId.
SSH operator fallback
--via ssh runs the same sessions.create on the Gateway host as the Gateway's
service user (OPENCLAW_HANDOFF_SSH_HOST, OPENCLAW_HANDOFF_REMOTE_CLI,
OPENCLAW_HANDOFF_REMOTE_USER). The session is then owned by the operator
identity, not the human. Use only when the human asks for it; never change
Gateway config or restart anything from this path.
Don'ts
- Do not drive the Gateway's web UI from an agent browser or sign in to the identity provider.
- Do not point the machine's primary
openclaw.jsonat the shared Gateway. - Do not poll session history in a loop.
| 1 | |
| 2 | name team-handoff |
| 3 | description "Hand local work to a shared OpenClaw Gateway: start a worktree session there as yourself in one request, seeded with a handoff, and get the session URL back." |
| 4 | |
| 5 | |
| 6 | # Team Handoff |
| 7 | |
| 8 | Use when the user says "open a session on the team server for this", "hand this |
| 9 | off to <team agent>", or "summarize this for a new agent and start it on |
| 10 | <gateway>", and the target is a shared OpenClaw Gateway behind an identity-aware |
| 11 | proxy (Cloudflare Access). |
| 12 | |
| 13 | One Gateway request, as the operator's own identity. No browser automation, no |
| 14 | SSH, no polling. |
| 15 | |
| 16 | Script: `scripts/team-handoff.sh` |
| 17 | |
| 18 | ## Setup (once per machine) |
| 19 | |
| 20 | Operator config, outside any repo: |
| 21 | `${XDG_CONFIG_HOME:-~/.config}/openclaw/team-handoff.env` |
| 22 | |
| 23 | |
| 24 | OPENCLAW_HANDOFF_URL=https://gateway.example # the shared Gateway's public origin |
| 25 | OPENCLAW_HANDOFF_AGENT=main # default agent id on that Gateway |
| 26 | OPENCLAW_HANDOFF_PROJECT=example-project # default projects.list id |
| 27 | # optional: |
| 28 | # OPENCLAW_HANDOFF_CLI=/path/to/openclaw # installed OpenClaw CLI (default: openclaw on PATH) |
| 29 | # OPENCLAW_HANDOFF_PROFILE_DIR=~/.openclaw/profiles/team |
| 30 | # OPENCLAW_HANDOFF_SSH_HOST=gateway-host # operator fallback only; see below |
| 31 | |
| 32 | |
| 33 | Isolated CLI profile so the local Gateway config is never touched. The script |
| 34 | writes it on first `probe` when missing: `OPENCLAW_STATE_DIR` and |
| 35 | `OPENCLAW_CONFIG_PATH` point at the profile dir, whose `openclaw.json` holds |
| 36 | only `gateway.mode: "remote"`, `gateway.remote.url`, and an `exec` secret |
| 37 | provider that runs `cloudflared access token -app=<url>` for the |
| 38 | `Cf-Access-Token` header (`gateway.remote.edgeAuth`, see the OpenClaw |
| 39 | docs page "Remote access", section "Gateway behind an identity-aware proxy"). |
| 40 | The provider `command` must be the real `cloudflared` binary, not a symlink. |
| 41 | |
| 42 | The human logs in once per Access session lifetime (agents cannot): |
| 43 | |
| 44 | |
| 45 | cloudflared access login https://gateway.example |
| 46 | |
| 47 | |
| 48 | `probe` prints `ok` when the chain works. `Exec provider "cloudflare-access" |
| 49 | exited with code 1` or an HTTP 302 on upgrade means the login lapsed: ask the |
| 50 | human to run it again; do not switch to the SSH fallback on your own. |
| 51 | |
| 52 | Why there is no token to mint: with `gateway.auth.mode: "trusted-proxy"` the |
| 53 | proxy authenticates the user and the Gateway maps the identity header to scopes; |
| 54 | first connection auto-pairs a CLI device with the proxy's `deviceAutoApprove` |
| 55 | scopes, which cover `sessions.create`. |
| 56 | |
| 57 | ## Use |
| 58 | |
| 59 | |
| 60 | bash scripts/team-handoff.sh probe |
| 61 | bash scripts/team-handoff.sh create \ |
| 62 | --label "Installed-package entry cap durable fix" \ |
| 63 | --name tree-cap-fix --base origin/main \ |
| 64 | --message-file /path/to/handoff.md |
| 65 | bash scripts/team-handoff.sh status <sessionKey> |
| 66 | bash scripts/team-handoff.sh archive <sessionKey> <sessionId> |
| 67 | |
| 68 | |
| 69 | `create` prints `url:` in the Control UI form |
| 70 | `<origin>/chat/<agent>/<label-slug>-<session-key-uuid-without-dashes>`, plus the |
| 71 | session key and run id. Hand the human that URL. Creation returns before the |
| 72 | worktree is prepared; `running` with `worktree: null` right after is normal, and |
| 73 | the agent's first turn starts once the checkout binds. Read status once; do not |
| 74 | loop. |
| 75 | |
| 76 | ## Payload |
| 77 | |
| 78 | Branch first. Push the work, pass `--base <branch>`, keep the long handoff in |
| 79 | the branch (for example `.openclaw/handoff.md`); the message is then three |
| 80 | lines: what the branch is, what to do first, what not to do. Local files are |
| 81 | unreachable from the Gateway; commit them or summarize the numbers. |
| 82 | Without a branch, the whole handoff goes in `--message-file`: a one-line title |
| 83 | first (it becomes the session title and URL slug), then goal, verified facts |
| 84 | with numbers, owner files, the agreed plan and order, proof expectations, and |
| 85 | explicit non-goals. |
| 86 | Name scope boundaries when a local session keeps part of the work, so two |
| 87 | agents do not open duplicate PRs. |
| 88 | |
| 89 | ## Failure modes |
| 90 | |
| 91 | `managed worktree allocation lease .../capacity was lost`: the Gateway lost |
| 92 | its worktree capacity lease during a slow project refetch. A retry in the same |
| 93 | session then fails with `branch already exists: openclaw/<name>` because the |
| 94 | failed attempt leaked its branch. Create a new session with a different |
| 95 | `--name`; archive the dead one. |
| 96 | `chat.send` requires `idempotencyKey`; `sessions.patch` lifecycle changes |
| 97 | require `expectedSessionId`. |
| 98 | |
| 99 | ## SSH operator fallback |
| 100 | |
| 101 | `--via ssh` runs the same `sessions.create` on the Gateway host as the Gateway's |
| 102 | service user (`OPENCLAW_HANDOFF_SSH_HOST`, `OPENCLAW_HANDOFF_REMOTE_CLI`, |
| 103 | `OPENCLAW_HANDOFF_REMOTE_USER`). The session is then owned by the operator |
| 104 | identity, not the human. Use only when the human asks for it; never change |
| 105 | Gateway config or restart anything from this path. |
| 106 | |
| 107 | ## Don'ts |
| 108 | |
| 109 | Do not drive the Gateway's web UI from an agent browser or sign in to the |
| 110 | identity provider. |
| 111 | Do not point the machine's primary `openclaw.json` at the shared Gateway. |
| 112 | Do not poll session history in a loop. |
| 113 |
Discussion
Alternatives
Browse more free Claude skills or everything in Operations.