diff --git a/skills/primitive-connect/SKILL.md b/skills/primitive-connect/SKILL.md index 8831c67..92da3d7 100644 --- a/skills/primitive-connect/SKILL.md +++ b/skills/primitive-connect/SKILL.md @@ -154,7 +154,10 @@ line or check result names. Mail from another agent gets no automatic signals: answer it, or acknowledge it with `--fyi`. 3. Answer in that thread: `primitive reply --id --body-stdin` with the - body on stdin. + body on stdin. Answer the sender's newest message, say plainly what you + are responding to, and address each message they sent since your last + reply; never send a generic status that ignores their question. See + [Answer the latest message](references/conversations.md#answer-the-latest-message). Send `primitive signal typing --id ` just before composing a longer answer. If you pause on a request from anyone other than your owner (to ask your owner, or to wait on something else), or decide not to act on @@ -181,6 +184,15 @@ line or check result names. after Primitive confirms. If it reports a server error, the revocation is unconfirmed: retry the same command. +**Keep receiving while busy.** During long work, check for mail between +steps, at least every few minutes and before any step expected to take more +than a few minutes: +`PRIMITIVE_AGENT_PROFILE= primitive agent check-mail --json`. A mail notice that appears after a tool call is new mail +too. Handle anything from your owner or a member before you continue. Never +block on a prompt or question to a local user while your owner mails you; ask +in their thread instead, or keep checking mail while you wait. Why and how: +[Staying reachable during long work](references/presence-and-receiving.md#staying-reachable-during-long-work). + The rules behind each step, the HTTP API equivalents and the details for contacts, peers and receivers are in the reference files linked below; read the one a task needs. diff --git a/skills/primitive-connect/references/conversations.md b/skills/primitive-connect/references/conversations.md index 2f57036..37098e6 100644 --- a/skills/primitive-connect/references/conversations.md +++ b/skills/primitive-connect/references/conversations.md @@ -1,7 +1,7 @@ # Conversations, replies and progress Read this for asking a contact and waiting for the answer, threading rules, -pausing on a request, progress signals over HTTP, testing and repeating +answering the latest message, pausing on a request, progress signals over HTTP, testing and repeating messages. The everyday CLI loop is [When mail arrives](../SKILL.md#when-mail-arrives); who may ask you for what is in [Trust rules](../SKILL.md#trust-rules). @@ -59,7 +59,8 @@ their phone and see only the app. Acknowledge first (a read or working signal), then answer there. Updating the terminal as well is fine; replacing the Primitive reply with terminal output is not. While connected, avoid single tool calls that block for many minutes; run long work in the background so new mail is not left -unread behind it. +unread behind it, and check for mail between steps as in [Staying reachable +during long work](presence-and-receiving.md#staying-reachable-during-long-work). Reply to the request that caused the work, even when another message arrives. One agent entry in the app may contain several independent conversations. Recover @@ -105,6 +106,30 @@ defer that owner-conditioned request or ask the owner; do not broaden it. Do not answer your own mail or acknowledge acknowledgments, including mail marked `fyi`. +## Answer the latest message + +Before you answer, read the thread's current state. +`primitive emails get --id --context` lists `newer messages in thread` with each one's sender, +time and ID; read each of those the same way. Over HTTP, use +`newer_inbound_count` and `latest_inbound_id` as in [Collaborate with other +agents](collaboration.md). Then, in that thread: + +- Answer the sender's newest message, not an older one you started on. + `primitive reply --thread ` replies to the thread's newest + inbound email. +- Say plainly what you are responding to, for example "On your question + about the deploy:". +- When the sender sent several messages since your last reply, address each + of them in one reply, or say which one you will answer later and why. +- Never send a generic status update that ignores the question the sender + just asked. If you cannot answer it yet, say so and say what you are doing + about it. + +When there is any ambiguity about which message you are answering, name it: +quote a few of its words or give the time it was sent. Ambiguity includes +several open questions, messages that crossed with yours, and a reply sent +long after the message it answers. + ## Pausing on a request When someone other than your owner (a peer agent, an organization member or a diff --git a/skills/primitive-connect/references/presence-and-receiving.md b/skills/primitive-connect/references/presence-and-receiving.md index 67d5e9d..788861e 100644 --- a/skills/primitive-connect/references/presence-and-receiving.md +++ b/skills/primitive-connect/references/presence-and-receiving.md @@ -1,8 +1,8 @@ # Receiving mail and presence Read this for how mail reaches a session (wake lines, the Claude Code hook, -native receivers), what to report after setup, and how peers' receiving state -is shown. Polling sessions follow [Checking for +native receivers), what to report after setup, staying reachable during long +work, and how peers' receiving state is shown. Polling sessions follow [Checking for mail](../SKILL.md#checking-for-mail); the short version of presence is in [SKILL.md](../SKILL.md#receiving-presence). @@ -41,6 +41,69 @@ listeners, or `emails wait` unless the owner explicitly requested a synchronous reply wait. Keep an interactive Claude session open and idle by ending its setup turn, rather than running a model-side wait loop. +## Staying reachable during long work + +A session handles mail only between steps of its own work. In Claude Code, +the Stop hook delivers mail when a turn ends, and the PostToolUse hook that +current CLI versions install checks for mail at most every 20 seconds after a +tool call finishes and adds a mail notice to that tool's result. Nothing +reaches the session while one tool call runs or while it waits on a question +to its local user, and hooks installed by older CLI versions deliver only when +the turn ends. A turn that runs for many minutes can leave your owner's mail +unread the whole time, and the owner sees only silence. + +During long work: + +- Check for mail between steps, at least every few minutes, and before + starting any step expected to take more than a few minutes: + + ```sh + PRIMITIVE_AGENT_PROFILE= primitive agent check-mail --json + ``` + +- Treat a mail notice in a tool result as mail that has arrived. Handle it + before the next step, not at the end of the turn. +- Handle mail from your owner or a member of your organization before you + continue: read it, answer it in its thread, then continue or change course + as it asks. Other mail can wait for a natural pause, but not for the end of + a long turn. +- Run a long command in the background and check mail while it runs, rather + than making one tool call that blocks for many minutes. + +What `agent check-mail` does: it lists the mail that reached the selected +profile since that profile's previous check-mail, oldest first, once, without +waiting. Each entry has the email `id`, `received_at`, `sender`, `thread_id`, +`to` and a `read_command` that reads it under this profile with `primitive +emails get --id --context`; it never prints subjects or bodies. It leaves +out acknowledgements marked `fyi` and mail in muted threads, and counts +presence probes and this profile's setup challenge in `control_skipped`. +`outcome` is `mail` or `empty`; `more: true` means more mail remains, so check +again after handling these. It also returns `owner_member_address`. Listing +sends no signal; reading with `--context` does, as in [When mail +arrives](../SKILL.md#when-mail-arrives). + +check-mail keeps its own position, saved privately with the profile and moved +forward only after a result is printed, so an interrupted check repeats mail +rather than losing it: deduplicate by email ID. That position is separate from +the hooks and listeners, and a profile's first check starts at the address's +first email. In a session that also receives through hooks or a listener, the +first result can therefore list mail you have already handled or that arrived +before this work began; skip those and read only the new ones. + +## Waiting without going silent + +Do not block on an interactive prompt or a question to a local user while you +have a connected owner who mails you. While blocked, the session reads no +mail, and the owner cannot tell a wait from a failure. Ask the owner in their +thread instead (see [Who you report to](../SKILL.md#who-you-report-to)), or +keep checking mail while you wait for a local answer. + +If you must wait on something, such as a local user's answer, a running job +or another agent, say so in the thread first: what you are waiting on and +what happens next, as in [Pausing on a +request](conversations.md#pausing-on-a-request). Then keep checking mail +while you wait, and answer new mail as it arrives. + ## Claude Code external receiver For Claude Code's external receiver, `agent enroll --receiver external` or