From 2c7c766152c4e6d6fa401625c2d1e858f8c0daa9 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:06:23 -0700 Subject: [PATCH 01/11] Send a Session-Prompt Command in a Plain Message, Never in a Blocking Prompt Split the "Communicating with the User" command bullet by where the command runs. A command run somewhere else stays in the question text. A command run at this session's own prompt goes in a plain message as a fenced block, the turn ends with no interactive prompt open, and the agent reads the result back on the user's next message. The two neighboring prompt bullets name this as their one exception, and the agent-conduct and session-handoff include copies are regenerated. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 6 +++--- .agents/skills/session-handoff/SKILL.md | 6 +++--- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 6 +++--- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 6 +++--- .github/skills/agent-conduct/SKILL.md | 6 +++--- .github/skills/session-handoff/SKILL.md | 6 +++--- GOVERNANCE.md | 6 +++--- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index ed89b28ee..d8469e3f8 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,9 +77,9 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 20debee17..ef5963987 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -295,9 +295,9 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index f857d9bf9..a01a5c3dd 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -617d316bfb422d7b +92f151cfa97b74fe diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index cf7af7320..29ad13618 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -c06c3fabab4420a1 +a9e873d733aa2fd4 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index ed89b28ee..d8469e3f8 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,9 +77,9 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 20debee17..ef5963987 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -295,9 +295,9 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index ed89b28ee..d8469e3f8 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,9 +77,9 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 20debee17..ef5963987 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -295,9 +295,9 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 912d6b948..f55f2acbd 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,9 +254,9 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run in the question's own text.** Where a question asks the user to run something, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because the command prompts for a password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. From 25700facc29e69346ff21e0249773c364dab49cc Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:09:17 -0700 Subject: [PATCH 02/11] Tighten the Session-Prompt Command Split After Local Review Ask the user to reply once the command has run, hold any other question until that reply, and accept the command's output as a read-back where it changes no state. Drop the request-versus-question reason from the exception, which did not separate the two cases, and fix the password example and the "only" that the new half contradicted. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 4 ++-- .agents/skills/session-handoff/SKILL.md | 4 ++-- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 4 ++-- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 4 ++-- .github/skills/agent-conduct/SKILL.md | 4 ++-- .github/skills/session-handoff/SKILL.md | 4 ++-- GOVERNANCE.md | 4 ++-- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index d8469e3f8..a3ef50548 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,8 +77,8 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index ef5963987..083e90e5c 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -295,8 +295,8 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index a01a5c3dd..90de8d163 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -92f151cfa97b74fe +a827d59ae130c93d diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 29ad13618..bfddcdcb1 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -a9e873d733aa2fd4 +e251f197878feef9 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index d8469e3f8..a3ef50548 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,8 +77,8 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index ef5963987..083e90e5c 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -295,8 +295,8 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index d8469e3f8..a3ef50548 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,8 +77,8 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index ef5963987..083e90e5c 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -295,8 +295,8 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index f55f2acbd..4f4c3a938 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,8 +254,8 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs somewhere else goes in the question's own text.** Where a question asks the user to run something outside this session, the question carries the exact command, complete and ready to paste. One example is a command the agent cannot run itself because it prompts for a password in another terminal. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. In the clickable-link bullet above, only the rendered link moves out of the prompt. A command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message, by reading back the state the command was meant to change. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one request that goes in a plain message, per the command bullet above. It is a request to act rather than a question, and the prompt this bullet calls for would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. From f9d60d8d76d32b20da1688dab509a8b8f884366b Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:11:40 -0700 Subject: [PATCH 03/11] Place the Session-Prompt Command First and Name What Decides Its Place Open the plain message with the command rather than closing a report with it, carry any other question owed that turn as the numbered-list fallback, name typed input as what sends a command outside the session, and narrow the neighboring exceptions to replacing the interactive prompt only. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 6 +++--- .agents/skills/session-handoff/SKILL.md | 6 +++--- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 6 +++--- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 6 +++--- .github/skills/agent-conduct/SKILL.md | 6 +++--- .github/skills/session-handoff/SKILL.md | 6 +++--- GOVERNANCE.md | 6 +++--- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index a3ef50548..90034f57b 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,9 +77,9 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 083e90e5c..7b2f3cb47 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -295,9 +295,9 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index 90de8d163..2c5b9af3d 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -a827d59ae130c93d +96b3059b03ee6715 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index bfddcdcb1..52b4e080c 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -e251f197878feef9 +fec26bc5fe18b533 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index a3ef50548..90034f57b 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,9 +77,9 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 083e90e5c..7b2f3cb47 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -295,9 +295,9 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index a3ef50548..90034f57b 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,9 +77,9 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 083e90e5c..7b2f3cb47 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -295,9 +295,9 @@ the asking falls to the next session that has one. The rules below settle which - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 4f4c3a938..5a34aec4f 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,9 +254,9 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. One example is a command that prompts for a password, which the user runs in another terminal because the agent cannot type the password. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes waits for that reply. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is the one exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Work blocked on a command the user runs at this session's own prompt follows the command bullet above instead. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. - **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. From 7f86f5a92ee9a62d269f90e3f40306bdb144383a Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:14:33 -0700 Subject: [PATCH 04/11] Carry a Command Turn's Questions in Its Message and Order Them Let a turn asking for a session-prompt command put every question it owes in that message, across the ask, blocked-work, and handoff bullets and the session-handoff skill's own fallback lines. State the order as the fenced block, then the numbered list, then any report, and say the block holds the `!` line itself. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 8 ++++---- .agents/skills/session-handoff/SKILL.md | 13 +++++++------ .../fleet-skills/.source-digests/agent-conduct | 2 +- .../fleet-skills/.source-digests/session-handoff | 2 +- .../fleet-skills/skills/agent-conduct/SKILL.md | 8 ++++---- .../fleet-skills/skills/session-handoff/SKILL.md | 13 +++++++------ .github/skills/agent-conduct/SKILL.md | 8 ++++---- .github/skills/session-handoff/SKILL.md | 13 +++++++------ GOVERNANCE.md | 8 ++++---- 9 files changed, 39 insertions(+), 36 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index 90034f57b..34d489fee 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,12 +77,12 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 7b2f3cb47..3ff3347fe 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -240,7 +240,7 @@ the whole procedure below. Run every step without being reminded of any of them. asked for as a prompt whose option names the action. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as - the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists. + the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's own prompt. 6. **Close the session** per "Closing a Session" below, which records lessons, writes the next round with `new`, presents the parked decision queue, and saves memories last. Where the issue carries the `blocked` label left on in step 3, take it off once the next round is written. Remove it with @@ -288,19 +288,20 @@ way. A reader who stops after the obligation has it with no shape to put it in. Recording the queue is not asking it. The handoff's "The parked decision queue" section is the recording half. What the other half is depends on what the session can reach. It is a prompt where -one is available, and the numbered list where a user is present and no prompt is. It is nothing at +one is available, and the numbered list where a user is present and no prompt is. The numbered list +also serves a turn asking for a command run at the session's own prompt. It is nothing at all where no user is present. In that case the handoff names the whole queue by issue number, and the asking falls to the next session that has one. The rules below settle which case applies. - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index 2c5b9af3d..bae5081bd 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -96b3059b03ee6715 +217294229b776212 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 52b4e080c..862ec2313 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -fec26bc5fe18b533 +e30628fa5fc6f5db diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index 90034f57b..34d489fee 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,12 +77,12 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 7b2f3cb47..3ff3347fe 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -240,7 +240,7 @@ the whole procedure below. Run every step without being reminded of any of them. asked for as a prompt whose option names the action. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as - the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists. + the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's own prompt. 6. **Close the session** per "Closing a Session" below, which records lessons, writes the next round with `new`, presents the parked decision queue, and saves memories last. Where the issue carries the `blocked` label left on in step 3, take it off once the next round is written. Remove it with @@ -288,19 +288,20 @@ way. A reader who stops after the obligation has it with no shape to put it in. Recording the queue is not asking it. The handoff's "The parked decision queue" section is the recording half. What the other half is depends on what the session can reach. It is a prompt where -one is available, and the numbered list where a user is present and no prompt is. It is nothing at +one is available, and the numbered list where a user is present and no prompt is. The numbered list +also serves a turn asking for a command run at the session's own prompt. It is nothing at all where no user is present. In that case the handoff names the whole queue by issue number, and the asking falls to the next session that has one. The rules below settle which case applies. - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index 90034f57b..34d489fee 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,12 +77,12 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 7b2f3cb47..3ff3347fe 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -240,7 +240,7 @@ the whole procedure below. Run every step without being reminded of any of them. asked for as a prompt whose option names the action. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as - the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists. + the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's own prompt. 6. **Close the session** per "Closing a Session" below, which records lessons, writes the next round with `new`, presents the parked decision queue, and saves memories last. Where the issue carries the `blocked` label left on in step 3, take it off once the next round is written. Remove it with @@ -288,19 +288,20 @@ way. A reader who stops after the obligation has it with no shape to put it in. Recording the queue is not asking it. The handoff's "The parked decision queue" section is the recording half. What the other half is depends on what the session can reach. It is a prompt where -one is available, and the numbered list where a user is present and no prompt is. It is nothing at +one is available, and the numbered list where a user is present and no prompt is. The numbered list +also serves a turn asking for a command run at the session's own prompt. It is nothing at all where no user is present. In that case the handoff names the whole queue by issue number, and the asking falls to the next session that has one. The rules below settle which case applies. - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 5a34aec4f..f4887c7d0 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,12 +254,12 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, opening it ahead of any report, as a fenced block complete and ready to paste. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. Any question the same turn owes goes in that message as a numbered list, the fallback the next bullet names. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A command the user runs at this session's own prompt is an exception, per the command bullet above. A prompt open on it would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. Where the work waits on a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. From 3522e656712bb0d674e5905bc7581fcf5821db09 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:17:27 -0700 Subject: [PATCH 05/11] Name the Session's Input Line Apart From the Interactive Prompt Call the place a `!` line is typed the session's input line, so it no longer shares a word with the interactive prompt beside it. Keep an outside command in the prompt only where the turn opens one, and move the inserted numbered-list sentences so the existing "That is the fallback" and "It is nothing at all" sentences keep their referents. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 8 ++++---- .agents/skills/session-handoff/SKILL.md | 14 +++++++------- .../fleet-skills/.source-digests/agent-conduct | 2 +- .../fleet-skills/.source-digests/session-handoff | 2 +- .../fleet-skills/skills/agent-conduct/SKILL.md | 8 ++++---- .../fleet-skills/skills/session-handoff/SKILL.md | 14 +++++++------- .github/skills/agent-conduct/SKILL.md | 8 ++++---- .github/skills/session-handoff/SKILL.md | 14 +++++++------- GOVERNANCE.md | 8 ++++---- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index 34d489fee..09584e5e6 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,12 +77,12 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 3ff3347fe..cfc69f32d 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -240,7 +240,7 @@ the whole procedure below. Run every step without being reminded of any of them. asked for as a prompt whose option names the action. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as - the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's own prompt. + the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. 6. **Close the session** per "Closing a Session" below, which records lessons, writes the next round with `new`, presents the parked decision queue, and saves memories last. Where the issue carries the `blocked` label left on in step 3, take it off once the next round is written. Remove it with @@ -288,20 +288,20 @@ way. A reader who stops after the obligation has it with no shape to put it in. Recording the queue is not asking it. The handoff's "The parked decision queue" section is the recording half. What the other half is depends on what the session can reach. It is a prompt where -one is available, and the numbered list where a user is present and no prompt is. The numbered list -also serves a turn asking for a command run at the session's own prompt. It is nothing at +one is available, and the numbered list where a user is present and no prompt is. It is nothing at all where no user is present. In that case the handoff names the whole queue by issue number, and the asking falls to the next session that has one. The rules below settle which case applies. +The numbered list also serves a turn asking for a command run at the session's input line. - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index bae5081bd..f273dc048 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -217294229b776212 +8649bb10c9a58968 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 862ec2313..7f4cdafe4 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -e30628fa5fc6f5db +2c827e029b818655 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index 34d489fee..09584e5e6 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,12 +77,12 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 3ff3347fe..cfc69f32d 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -240,7 +240,7 @@ the whole procedure below. Run every step without being reminded of any of them. asked for as a prompt whose option names the action. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as - the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's own prompt. + the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. 6. **Close the session** per "Closing a Session" below, which records lessons, writes the next round with `new`, presents the parked decision queue, and saves memories last. Where the issue carries the `blocked` label left on in step 3, take it off once the next round is written. Remove it with @@ -288,20 +288,20 @@ way. A reader who stops after the obligation has it with no shape to put it in. Recording the queue is not asking it. The handoff's "The parked decision queue" section is the recording half. What the other half is depends on what the session can reach. It is a prompt where -one is available, and the numbered list where a user is present and no prompt is. The numbered list -also serves a turn asking for a command run at the session's own prompt. It is nothing at +one is available, and the numbered list where a user is present and no prompt is. It is nothing at all where no user is present. In that case the handoff names the whole queue by issue number, and the asking falls to the next session that has one. The rules below settle which case applies. +The numbered list also serves a turn asking for a command run at the session's input line. - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index 34d489fee..09584e5e6 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,12 +77,12 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 3ff3347fe..cfc69f32d 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -240,7 +240,7 @@ the whole procedure below. Run every step without being reminded of any of them. asked for as a prompt whose option names the action. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as - the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's own prompt. + the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. 6. **Close the session** per "Closing a Session" below, which records lessons, writes the next round with `new`, presents the parked decision queue, and saves memories last. Where the issue carries the `blocked` label left on in step 3, take it off once the next round is written. Remove it with @@ -288,20 +288,20 @@ way. A reader who stops after the obligation has it with no shape to put it in. Recording the queue is not asking it. The handoff's "The parked decision queue" section is the recording half. What the other half is depends on what the session can reach. It is a prompt where -one is available, and the numbered list where a user is present and no prompt is. The numbered list -also serves a turn asking for a command run at the session's own prompt. It is nothing at +one is available, and the numbered list where a user is present and no prompt is. It is nothing at all where no user is present. In that case the handoff names the whole queue by issue number, and the asking falls to the next session that has one. The rules below settle which case applies. +The numbered list also serves a turn asking for a command run at the session's input line. - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index f4887c7d0..28e4e3662 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,12 +254,12 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's own prompt never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's prompt so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's prompt. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. -- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's own prompt is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". -- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's prompt, the command bullet above replaces the interactive prompt. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". +- **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. - **A question filed as an issue is parked rather than asked, and it stays owed.** Where the work cannot continue without the answer, the interactive-prompt bullet governs and the question is asked at the point the work stops. Wherever the question is recorded rather than asked, recording it is the right thing to do, and recording it is still not asking it. That holds whether the work can continue without the answer or the question was asked once and deferred. So the issue carries the fleet's `decision` label. When the filing session knows the choices the question is between, the issue states them. The label and the stated choices are what let a later session, one that was not there when the issue was filed, find the question. That session can then put the question to the user without inventing its answers. **The parked queue is the failure, not the parking.** An issue holding a question the user has never seen reads to every later session as tracked work rather than as a block. So each session files correctly and moves on. Presenting the accumulation is the step nobody owns. -- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. So do they in a turn asking for a command the user runs at this session's own prompt. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. +- **The session that writes a handoff presents the parked queue in the same act.** This binds at the moment the session writes the handoff that `AGENTS.md` "Session Scope" defines, rather than at the moment the session ends. That is because a session also ends by interruption, where no agent acts at all and no rule reaches it. The session enumerates this repository's open issues carrying that label, and states how many issues the queue holds. It puts the highest-ranked of them to the user as questions, **one question per parked decision, carrying that decision's own answers as its options**. That is the interactive-prompt bullet's own shape applied per decision, rather than a single prompt whose options are topics. An issue that states no choices is put as the open question it is, never as invented options. That is because the label marks every decision waiting on the user, rather than only the ones filed under this rule. It is also because the issues that already carry the label predate the rule. Rank them longest-waited first. Every issue records how long it has waited, so any session can reproduce that order. Promote one ahead of that order where it blocks work in flight, and say in the handoff that it was promoted. That is because two sessions order the same queue differently where the key is subjective and nobody records it. Where more are parked than one round of questions can carry, the stated count still covers every one of them. The handoff names the remainder by issue number in that order, a list of numbers rather than of questions. That is what keeps the handoff inside the size rule that `AGENTS.md` "Session Scope" sets for it. **A count nobody states is a queue nobody can see**, which is how a backlog reported as healthy hides the questions inside it. Where a user is present but no prompt mechanism is available, the questions go as a numbered list. That is the fallback the interactive-prompt bullet already names, and it reaches a reader who is there to read it. They go as a numbered list too in a turn asking for a command the user runs at this session's input line. Where no user is present at all, the session asks nothing and names the whole queue by issue number in the handoff. It leaves the asking to the next session that has one. An item leaves the queue when the user answers it, and also at triage where a later change has already answered or overtaken its decision. Either way it leaves by losing the label, with the answer or the reason recorded on the issue. The issue itself closes only where it held nothing but the question. That is because the queue holds issues that outlive their decision. It is also because closing such an issue just to clear the queue discards the other work that issue tracks. `GOVERNANCE.md` "Communicating with the User" keeps the full rules. The `agent-conduct` and `session-handoff` Skills at `.agents/skills/agent-conduct/SKILL.md` and `.agents/skills/session-handoff/SKILL.md` in the hub each carry it whole as a generated include. Each surfaces it at its own decision moment. Those paths are not repo-relative links, since they are hub-local and not carried into every fleet repo. From 15804970d37c06449dfa689e267a6aae4d3a0496 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:20:10 -0700 Subject: [PATCH 06/11] Join Several Session-Input Commands on One Line Only the first line of a pasted block reaches shell mode, so several commands for the session's input line join on one `!` line with `&&` rather than sitting as separate lines in the block. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 2 +- .agents/skills/session-handoff/SKILL.md | 2 +- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 2 +- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 2 +- .github/skills/agent-conduct/SKILL.md | 2 +- .github/skills/session-handoff/SKILL.md | 2 +- GOVERNANCE.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index 09584e5e6..b04fac3ba 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index cfc69f32d..b9542cc40 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index f273dc048..8f31576c3 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -8649bb10c9a58968 +f98481f5040edf03 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 7f4cdafe4..afab45dba 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -2c827e029b818655 +6b49b44c88f83618 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index 09584e5e6..b04fac3ba 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index cfc69f32d..b9542cc40 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index 09584e5e6..b04fac3ba 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index cfc69f32d..b9542cc40 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 28e4e3662..67877fc9b 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,7 +254,7 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. From bdce055f647ec78138aad89d46fe4cc94d510e67 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:23:13 -0700 Subject: [PATCH 07/11] State the Test That Places a Command and What `&&` Does Open the command bullet with the test itself, typed input sends a command outside the session and every other one runs at the session's input line, rather than a circular "depends on where it runs". Say that `&&` stops at the first command that fails. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 2 +- .agents/skills/session-handoff/SKILL.md | 2 +- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 2 +- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 2 +- .github/skills/agent-conduct/SKILL.md | 2 +- .github/skills/session-handoff/SKILL.md | 2 +- GOVERNANCE.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index b04fac3ba..510e0ff14 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index b9542cc40..64bc89ec0 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index 8f31576c3..7bddbac39 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -f98481f5040edf03 +898778e1bad1d014 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index afab45dba..a6052e74e 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -6b49b44c88f83618 +1b1d945a38df4346 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index b04fac3ba..510e0ff14 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index b9542cc40..64bc89ec0 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index b04fac3ba..510e0ff14 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index b9542cc40..64bc89ec0 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 67877fc9b..a1b68beac 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,7 +254,7 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** Which place that is depends on where the command runs. **A command the user runs outside this session goes in the question's own text.** One that reads typed input as it runs, such as a password prompt, belongs there. Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line, where the user types to the agent, never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. It suits a command reading no typed input whose output the agent needs. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, so one paste runs them all. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. From 6816072f6531a918981100d33eb9ce42e8217c00 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:26:00 -0700 Subject: [PATCH 08/11] Place a Command by Whether This Session's Environment Can Run It Widen the placement test from typed input alone to any command this session's environment cannot run, another host's included, give a command a place on a harness with no input line, and restore "The command" where a bare "It" read as the link. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 2 +- .agents/skills/session-handoff/SKILL.md | 2 +- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 2 +- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 2 +- .github/skills/agent-conduct/SKILL.md | 2 +- .github/skills/session-handoff/SKILL.md | 2 +- GOVERNANCE.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index 510e0ff14..dd15358ba 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 64bc89ec0..72fcc17cf 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index 7bddbac39..faeb9cc74 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -898778e1bad1d014 +6b1c822029c4db7a diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index a6052e74e..26e65617a 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -1b1d945a38df4346 +fa205209a76051b8 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index 510e0ff14..dd15358ba 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 64bc89ec0..72fcc17cf 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index 510e0ff14..dd15358ba 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 64bc89ec0..72fcc17cf 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index a1b68beac..ea504bacf 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,7 +254,7 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that reads typed input as it runs, such as a password prompt, runs outside this session. Every other one runs at this session's input line, the place the user types to the agent, where the harness offers that. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. It needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. From 533f61a087be6e77d2e31fd725d98c8331d54b00 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:29:47 -0700 Subject: [PATCH 09/11] Test Whether the Input Line Can Run a Command and Hold Its Effect Send a command outside the session where the session cannot run it or cannot hold its effect, a launch-time variable among the examples, and use the input line only where that line can run a command. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 2 +- .agents/skills/session-handoff/SKILL.md | 2 +- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 2 +- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 2 +- .github/skills/agent-conduct/SKILL.md | 2 +- .github/skills/session-handoff/SKILL.md | 2 +- GOVERNANCE.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index dd15358ba..21e1d70b5 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 72fcc17cf..42e384f57 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index faeb9cc74..e76451841 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -6b1c822029c4db7a +d153c83f5c91811f diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 26e65617a..9815b0e87 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -fa205209a76051b8 +5629aa6ba8487b24 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index dd15358ba..21e1d70b5 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 72fcc17cf..42e384f57 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index dd15358ba..21e1d70b5 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 72fcc17cf..42e384f57 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -296,7 +296,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index ea504bacf..44f8b3266 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,7 +254,7 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** A command that cannot run in this session's environment runs outside it. One reading typed input as it runs, such as a password prompt, is such a command, and so is one meant for another host. Every other one runs at this session's input line, or outside the session where the harness has none. The input line is where the user types to the agent. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. From 1b97c3bc6068dac4df43143798a3a8ac36ed7c86 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:33:13 -0700 Subject: [PATCH 10/11] Key the Placement Test on the Input Line and Align Handoff Step 4 Name the session's input line, not the agent's own tool, as what the placement test asks about, and let session-handoff step 4's go-ahead follow step 5 in a turn that asks for an input-line command. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 2 +- .agents/skills/session-handoff/SKILL.md | 5 +++-- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 2 +- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 5 +++-- .github/skills/agent-conduct/SKILL.md | 2 +- .github/skills/session-handoff/SKILL.md | 5 +++-- GOVERNANCE.md | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index 21e1d70b5..2a057eb5b 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index 42e384f57..e88c9bb1c 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -237,7 +237,8 @@ the whole procedure below. Run every step without being reminded of any of them. request with `drive-pr` to a mergeable develop -> main promotion pull request. The phrase already states that target, so `drive-pr` does not ask how far. Merging that promotion pull request and dispatching a release stay `merge-and-release`. Each needs an explicit go-ahead, - asked for as a prompt whose option names the action. + asked for as a prompt whose option names the action. A turn asking for a command run at the + session's input line asks for it per step 5 instead. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. @@ -296,7 +297,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index e76451841..ca84d2cf4 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -d153c83f5c91811f +3fe89471dfd93d51 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 9815b0e87..db2c20e8b 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -5629aa6ba8487b24 +49cf5469ec5e651c diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index 21e1d70b5..2a057eb5b 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index 42e384f57..e88c9bb1c 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -237,7 +237,8 @@ the whole procedure below. Run every step without being reminded of any of them. request with `drive-pr` to a mergeable develop -> main promotion pull request. The phrase already states that target, so `drive-pr` does not ask how far. Merging that promotion pull request and dispatching a release stay `merge-and-release`. Each needs an explicit go-ahead, - asked for as a prompt whose option names the action. + asked for as a prompt whose option names the action. A turn asking for a command run at the + session's input line asks for it per step 5 instead. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. @@ -296,7 +297,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index 21e1d70b5..2a057eb5b 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index 42e384f57..e88c9bb1c 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -237,7 +237,8 @@ the whole procedure below. Run every step without being reminded of any of them. request with `drive-pr` to a mergeable develop -> main promotion pull request. The phrase already states that target, so `drive-pr` does not ask how far. Merging that promotion pull request and dispatching a release stay `merge-and-release`. Each needs an explicit go-ahead, - asked for as a prompt whose option names the action. + asked for as a prompt whose option names the action. A turn asking for a command run at the + session's input line asks for it per step 5 instead. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. @@ -296,7 +297,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 44f8b3266..478dec0b6 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,7 +254,7 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where the session cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. From f091795b6fdeef838bfbd63661aaaf58af728383 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 30 Oct 2026 00:36:38 -0700 Subject: [PATCH 11/11] Name Typed Input as the Property and the Go-Ahead as What Step 5 Asks Widen the outside-session example from a typed password to any command waiting on typed input, and say session-handoff step 4 asks for the go-ahead, not the command, per step 5. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/agent-conduct/SKILL.md | 2 +- .agents/skills/session-handoff/SKILL.md | 4 ++-- .claude-plugin/fleet-skills/.source-digests/agent-conduct | 2 +- .claude-plugin/fleet-skills/.source-digests/session-handoff | 2 +- .claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md | 2 +- .claude-plugin/fleet-skills/skills/session-handoff/SKILL.md | 4 ++-- .github/skills/agent-conduct/SKILL.md | 2 +- .github/skills/session-handoff/SKILL.md | 4 ++-- GOVERNANCE.md | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.agents/skills/agent-conduct/SKILL.md b/.agents/skills/agent-conduct/SKILL.md index 2a057eb5b..b73b6f980 100644 --- a/.agents/skills/agent-conduct/SKILL.md +++ b/.agents/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index e88c9bb1c..9002fe4c0 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -238,7 +238,7 @@ the whole procedure below. Run every step without being reminded of any of them. already states that target, so `drive-pr` does not ask how far. Merging that promotion pull request and dispatching a release stay `merge-and-release`. Each needs an explicit go-ahead, asked for as a prompt whose option names the action. A turn asking for a command run at the - session's input line asks for it per step 5 instead. + session's input line asks for the go-ahead per step 5 instead. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. @@ -297,7 +297,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/.source-digests/agent-conduct b/.claude-plugin/fleet-skills/.source-digests/agent-conduct index ca84d2cf4..ddedbcf9a 100644 --- a/.claude-plugin/fleet-skills/.source-digests/agent-conduct +++ b/.claude-plugin/fleet-skills/.source-digests/agent-conduct @@ -1 +1 @@ -3fe89471dfd93d51 +b27b756b8eae6533 diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index db2c20e8b..9a39cb49f 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -49cf5469ec5e651c +d6e2ed39334468a3 diff --git a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md index 2a057eb5b..b73b6f980 100644 --- a/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index e88c9bb1c..9002fe4c0 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -238,7 +238,7 @@ the whole procedure below. Run every step without being reminded of any of them. already states that target, so `drive-pr` does not ask how far. Merging that promotion pull request and dispatching a release stay `merge-and-release`. Each needs an explicit go-ahead, asked for as a prompt whose option names the action. A turn asking for a command run at the - session's input line asks for it per step 5 instead. + session's input line asks for the go-ahead per step 5 instead. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. @@ -297,7 +297,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/agent-conduct/SKILL.md b/.github/skills/agent-conduct/SKILL.md index 2a057eb5b..b73b6f980 100644 --- a/.github/skills/agent-conduct/SKILL.md +++ b/.github/skills/agent-conduct/SKILL.md @@ -77,7 +77,7 @@ Claims about a pull request being reviewed, clean, or mergeable are owned by the - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index e88c9bb1c..9002fe4c0 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -238,7 +238,7 @@ the whole procedure below. Run every step without being reminded of any of them. already states that target, so `drive-pr` does not ask how far. Merging that promotion pull request and dispatching a release stay `merge-and-release`. Each needs an explicit go-ahead, asked for as a prompt whose option names the action. A turn asking for a command run at the - session's input line asks for it per step 5 instead. + session's input line asks for the go-ahead per step 5 instead. 5. **Ask every question as a dialog.** Where the interface has a prompt mechanism, each decision is its own question with its answers as the options. There the recommended one comes first and is marked as the recommendation, and every one carries its reason, per "The Parked Decision Queue" below. The numbered list is the fallback where no prompt exists, or where the turn also asks for a command run at the session's input line. @@ -297,7 +297,7 @@ The numbered list also serves a turn asking for a command run at the session's i - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 478dec0b6..fff09f51e 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -254,7 +254,7 @@ The hub's `scripts/pr_review.py` implements the provider-specific mechanics this ## Communicating with the User - **Reference every pull request as a clickable link.** When you mention a PR on a surface that renders Markdown (chat, a summary, a report), render it as a Markdown link to the PR. Write it as `[#N](https://github.com/OWNER/REPO/pull/N)`, never a bare `#N`. The same applies to issues and commits. **The form follows the surface.** Some surfaces link neither a Markdown link nor a bare URL, an interactive prompt's question and option text among them. Pasting a full URL into one of those does not rescue it, since the reader gets a string to copy. That is the outcome this rule exists to prevent. There the reference is a bare `#N`. The clickable link goes in the message that comes **before** the prompt rather than merely alongside it. That is because the prompt blocks on an answer, and a message emitted after it is read once that answer is already given. That is the one moment the link is no longer any use. The test is whether the reader can click it where it is read, not whether it was written in the syntax that works elsewhere. -- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One reading a typed password, one meant for another host, and one setting a variable the session reads at launch are such commands. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. +- **Put a command the user must run where the user can run it.** This session's input line is where the user types to the agent. A command runs outside this session where this session's input line cannot run it or cannot hold its effect. One waiting on typed input, such as a password or a confirmation, is such a command. So is one meant for another host, or one setting a variable the session reads at launch. Every other one runs at this session's input line, where that line can run a command, and outside the session otherwise. **A command the user runs outside this session goes in the question's own text.** Where a question asks the user to run one, the question carries the exact command, complete and ready to paste. A message before the prompt may repeat the command, but the question never points at that message. A question pointing at it can leave the reader to find the command among a long run of earlier output. Such a command stays in the prompt, where the turn opens one, although the clickable-link bullet above moves a link out of one. The command needs no rendering, since the prompt shows it as plain text the reader can copy. **A command the user runs at this session's input line never goes in an interactive prompt.** On Claude Code such a command is a `!` line, typed at the session's input line so its output lands in the session. While an interactive prompt is open, the user cannot type at the session's input line. So a command placed in one sits in the one surface that blocks running it. It goes in a plain message instead, as a fenced block holding the `!` line itself, complete and ready to paste. Several commands join on that one line with `&&`, which runs them in order and stops at the first that fails. The block opens the message. Any question the same turn owes follows it as a numbered list, and any report comes after both. The message asks the user to reply once the command has run, and the turn ends with no interactive prompt open. The agent then checks the result on the user's next message. It reads back the state the command was meant to change, or the output it left in the session. An answer saying the command ran is not that check. - **Ask every question through the interface's prompt, never in prose.** When you need the user to decide, answer, or approve anything, put it to them through the interface's own prompt mechanism. Do so whether or not work is blocked on it. An offer to do more work ("want me to file that?") is a question like any other. A question written into a message is lost in the report around it, however short it is. One closing a long report sits where the reader is least likely to reach it. Where no prompt mechanism is available, the questions go as a numbered list opening the message rather than closing it. The user can then reply per number. A turn asking for a command the user runs at this session's input line is an exception, per the command bullet above. It puts every question it owes in that message, since a prompt open beside the command would block the place it runs. This bullet settles how a question is put once it is asked. Whether a question is asked now or recorded for later is the parking bullet's to settle. That is the one opening "A question filed as an issue is parked rather than asked". - **Raise work blocked on the user as a direct interactive prompt.** When progress needs a decision, an authorization, or an answer only the user can give, ask for it at the point the work stops. Ask through the interface's own prompt mechanism. Never leave it as prose in a summary. A handoff buried in a paragraph is a handoff that did not happen. That is because a summary reads as a report of finished work. It is also because the one line still waiting on the user is the easiest in a summary to skim past. The blocked item is the message, not a closing remark on a message about something else. **The options offered are the actions themselves.** The one that unblocks the work names the action it authorizes ("squash and merge it"). Selecting it is then the go-ahead rather than a note to act on later. Offering only ways to wait is the same failure in interactive clothing. That is because a prompt whose every choice is inaction reports the block rather than clearing it. Where the agent may not perform the authorized action itself, the option says who does it. Where no interactive prompt is available, the numbered list the bullet above names is the fallback. In a turn asking for a command the user runs at this session's input line, the command bullet above replaces the interactive prompt. - **Lead every choice with a recommendation and its reason.** Wherever the user is asked to choose, in a prompt or in a numbered list, the option the agent recommends comes first. It is marked as the recommendation, and every option states the reason for it. A user who takes the recommendation then reads one line, and one who does not sees what the other options trade away. A question with no defensible recommendation says so rather than inventing one. Where an open question has no options and the agent does have an answer, that answer and its reason go in the question's text. They never go in as an invented option.