Skip to content
Agentmart
Submit a tool

mail

Read, send, reply to, and manage Footnote agent mail from any session.

Skill by bllshttng

IndexedApache-2.0★ 2
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/bllshttng-mail

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Read, send, reply to, and manage Footnote agent mail from any session.

Use cases: agent-building

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Shell scripts

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/mail

What's inside

Skill name
mail
Description
Read, send, reply to, and manage Footnote agent mail from any session.
License
Apache-2.0
Metadata
internal: false
Instructions
298 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (4)

  • LIMITATIONS.md
  • SKILL.md
  • normalize.sh · scripts/
  • test_normalize.sh · tests/

SKILL.md (first lines)

# Mail

## Relay compression contract

Every agent-authored mail is a handoff: 80 words or fewer, outcome and next action only. The full contract (what to cut, what stays exact, the `Status:`/`Approval:` forms) is stated ONCE in the auto-loaded `skills/using-fno/SKILL.md`. A second copy here can drift from the one every session loads. Compress against that statement. Keep technical terms, commands, errors, numbers, and negation exact. This binds `fno agents mail send`, `fno agents mail reply`, and `fno mux pane send` alike.

**Message background workers and projects from anywhere - even your phone.**

`/fno:mail` is the runner-less front door over the shipped `fno agents mail`
messaging surface. `fno agents mail send|reply|unread|...` needs exact shell quoting, and
a phone has no `!` local-command runner, so a typed command either splits on bad
smart quotes or never executes at all. This skill fixes that the same way
`/agent` does: **you (the agent) are the runner.** You read the messy input,
route it to the right `fno agents mail` command, normalize it, run the **genuine** command
via your Bash tool, and report the **real** captured receipt.

`/agent` is agent **lifecycle** (spawn / watch / stop). `/mail` is **messaging**.
Two skills, two concerns. This skill REUSES the shipped `fno agents mail` primitives -
it does not reimplement the bus, the cursor, or the render. Its value is command
routing + input normalization + honest reporting for surfaces that cannot run a
local command.

`SKILL_DIR` below is `skills/mail` inside this plugin.

## The delivered turn: one header line, then the whole body

Delivered mail opens with one backticked line, `` `@sender · fmail-<12 hex> · summary` ``, and the full message follows, wholly visible. The summary is the body's first sentence capped at 12 words. The `@` lives inside inline code on purpose: a bare `@` in harness text can open a mention picker or read as an address, so each harness's contract row (`mail_header_at` in `harness_capabilities.toml`) rules which spelling its composer gets, set by the composer check. Old `<fno_mail>` turns in existing transcripts still resolve everywhere.

## The delivery model (so the commands make sense)

**A send injects into the recipient's live session. The durable queue is what
happens when that misses, and it is recovery, not delivery.**

`fno agents mail send` tries a live inject first. On success the header-framed turn lands in the recipient's session and an audit-only `delivery: hosted` row records it in `messages.jsonl`. Recipient drains ignore that row because delivery already happened. When no live inject confirms, the envelope instead enters the durable queue and waits on a drain the recipient does not reliably run. Both exit 0, so **read the receipt, not the exit code**:

- `msg-<id> accepted-new-turn` or `accepted-steer` - the recipient's own turn record holds the envelope id. It does not prove the recipient acted on it.
- `msg-<id> parked` or `injected` - the bytes reached the recipient, but no turn took them yet. Peek before you resend: a resend reaches it twice.
- `msg-<id> queued (durable)` - live delivery was not confirmed. This is durable fallback, not delivery.
- the receipt ends `landed (...)` or a `NOT LANDED` block - the send command re-checked the recipient after a settle window, and NOT LANDED names the recovery and verify commands for that substrate and exits non-zero (14).

The recipient's own `unread` / `ack` / `drain-self` commands exist to consume that
fallback queue, which is why they read like a mailbox. They are the recovery
path, not the main one.

### A miss is recoverable now - look before you re-send

A durable receipt usually means the session is idle rather than gone, and an idle
session can be brought back, so waiting on a drain is the last resort. But
"not confirmed" is not the same as "not delivered": a BUSY recipient can queue
the injected turn past the confirm budget and still receive it later, so a blind
re-send is how you double-deliver. Check first, then act:

```bash
fno agents session peek <short-id>     # did the turn actually land? is it alive?
fno agents session resume <short-id>   # wakes it (claude) or resumes it (other harnesses), then re-send
fno agents session attach <short-id>   # drive it yourself (claude)
```

Address a peer by its full session id: the `from_session=` value on the `<fno_mail>` envelope, or the id `fno agents session list` shows. The head-8 short form is a display handle. Under UUIDv7 it is a ~66-second clock bucket. Two workers started in the same minute share one, so a send or reply addressed to the short form can refuse as ambiguous. `resume` / `attach` accept the id that names the session in the registry, and `send` can reach a live session that never registered. If a handle mails but will not resume, `fno agents session list` / `top` will show whether it has a row.

A harness-prefixed address (`claude-<short-id>`) is refused, not translated. If you hit that error, something built the address the retired way - fix that, and do not hand-edit the string and move on.

No probe is proof a peer is dead. `peek`, discovery, a status token, and a claim pid can all read stale at once. A peer that ran `EnterWorktree` moved its transcript to a worktree-keyed project dir, so a probe pointed at the old path reads empty. The one authoritative pre-dead-declaration check is the session's transcript file itself (its worktree-keyed project dir, by mtime/tail). Any receipt or probe that names a store must say WHICH store it read.

## Command router

The first whitespace token of the argument is the **command**. Route on it, then run
the matching section. Messaging is free, so **nothing here confirms** (contrast
`/agent`, where `chat`/`stop` confirm).

| Command | Routes to | Needs normalize | Cost |
|------|-----------|-----------------|------|
| `send <name> "<body>"` | `fno agents mail send <name> "<body>"` | yes (refuse empty) | free |
| `send project <X> "<body>"` | `fno agents mail send --to-project <X> "<body>"` | yes (broadcast) | free |
| `reply <msg-id> "<body>"` | `fno agents mail reply --to <msg-id> --body "<body>"` | yes (refuse empty) | free |
| `unread [name]` | `fno agents mail unread [-n <name>]` | no (read) | free |
| `ack <msg-id> [name]` | `fno agents mail ack <msg-id> [-n <name>]` | no | free |
| `show [id]` | `fno agents mail show [id]` | no (read) | own session (--all lifts) |
| `hold [minutes\|off\|status]` | `/fno:dnd` (codex `$fno:dnd`) with the same argument | natural-language duration | free |
| `dnd [off\|cancel]` | `/fno:dnd` (codex `$fno:dnd`) with the same argument | no | free |

An unrecognized leading token is an error - tell the user the command set above; do
NOT guess a send. (Unlike `/agent`, a bare non-command is not a default action here,
because a misrouted `send` could publish a malformed message.)

---

## `send <name> "<body>"` - publish to a peer or a project

The core command (US4). Strip the leading `send`; the rest is `<recipient> <body>`
(name mode) or `project <X> <body>` / `--to-project <X> <body>` (broadcast mode).

### Flow: NORMALIZE -> RUN -> REPORT (no confirm: free lane)

#### 1. NORMALIZE (deterministic helper)

Run the normalizer with everything after the `send` command as ONE `--input`:

```bash
bash "${SKILL_DIR}/scripts/normalize.sh" --command send --input "<recipient/project + body>"
```

It strips smart quotes, splits the recipient (or detects a `project`/`to-project`
broadcast keyword) from the body, strips one wrapping quote pair off the body,
and **refuses an empty or whitespace-only recipient or body**. Read its
`key=value` output; never `eval` it. Fields: `status`, `error`, `command`,
`recipient`, `to_project`, `body`. `body` is emitted **last** and may span
multiple lines (a pasted multiline message is preserved intact), so capture
**everything after the `body=` marker** to end of output as the body - do not
truncate it at the first newline.

- If `status=error`, **STOP. Report the `error=` line and run nothing** (AC4-ERR).
- Otherwise capture `recipient` / `to_project` / `body`.

#### 2. RUN (genuine execution)

Run the real `fno agents mail send` - never reimplement the bus. Pass the body as a
single quoted argument exactly as normalize returned it:

From bllshttng/fno, Apache-2.0.

More from bllshttng/fno

Signals

Stars
2
Forks
0
Open issues
1
Last commit (this folder)
Oct 21, 2026 (8 days ago)
Last release
Oct 23, 2026 (6 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
Apache-2.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from bllshttng

Cite this page

mail skill. Agent Mart. https://agentmart.dev/skills/bllshttng-mail (last updated 2026-10-24)