Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion skills/primitive-connect/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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 <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
Expand All @@ -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=<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.
Expand Down
29 changes: 27 additions & 2 deletions skills/primitive-connect/references/conversations.md
Original file line number Diff line number Diff line change
@@ -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).
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 <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 <thread-id>` 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
Expand Down
67 changes: 65 additions & 2 deletions skills/primitive-connect/references/presence-and-receiving.md
Original file line number Diff line number Diff line change
@@ -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).

Expand Down Expand Up @@ -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=<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 <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
Expand Down
Loading