Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
61 changes: 61 additions & 0 deletions docs/upstream-issue-defaults.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Draft: the one upstream issue for default changes

lucid-max asked for **one issue** that lists every behaviour change we won't send as
a PR (answer 3 in [upstream-pr-strategy.md](upstream-pr-strategy.md)). The
operator files it in ignition-is-go/marshal. This file is the draft. The text
between the rules is the issue body.

Each item was checked against upstream main `9b00c6f` (v0.58.0) in `~/src/marshal`
on 2026-11-05. Items upstream already covers have been dropped (see the end).

---

**Title:** Behaviour changes from the Muster fork, for you to take or leave

We run a fork of Marshal and are sending its additive work back one small PR at a
time. These are the changes that would alter what a user who changes nothing sees,
so we're listing them for you to pick from rather than sending them as PRs. They're
in no particular order. We're glad to turn any of them into a PR, or to leave it for
you to reimplement, whichever you prefer.

1. **Refuse an empty `to` on `send_message`.** Today `resolve_recipient("")`
reaches the session-id prefix step, where every id starts with `""`. With one
session registered, that's the sender, so the message goes to the sender itself.
With several, the caller gets an "ambiguous" error that lists every session. We
refuse an empty or whitespace-only `to` up front with a plain error.
2. **Hold a session's first write until it's registered.** A write in the first
moments after the shim starts, before the session is registered, is rejected as
unregistered. Agents often send first thing, so they hit that error. We hold the
first write for up to 5 s while registration finishes, and retry it once if the
daemon refuses it as unregistered.
3. **Keep a waiting session through a dropped connection.** A WS-shim session
without a live client is reaped after `STALE_AFTER` (60 s), even while a hook
waiter is still holding `/hook/wait` for it. We keep the session for as long as a
waiter is held. A session that's idle but listening then stays on the roster and
reachable.
4. **Codex threads re-register after a daemon restart.** After a restart, an idle
Codex session doesn't reappear on the roster until its next hook. We have the
bridge re-register its known threads when it reconnects, so they show again
straight away.
5. **Frame peer bodies in the hook inbox as quoted text.** Your #141 already
escapes `&`, `<` and `>` and marks peer mail as untrusted. Our version also quotes
each body, so it can't pose as another inbox line. That's a small difference, and
we're fine dropping it if escaping is enough for you.

Already in your main, so not listed: keeping mail for a reaped recipient. Direct
messages and read marks now survive the DEL, and `MESSAGE_TTL` (14 days) is the
only thing that removes them.

---

## Notes for the operator (not part of the issue)

- Items 1–3 were checked in upstream code: `entities/src/send_message.rs`
`resolve_recipient`, the shim's unregistered rejection, and `daemon/src/cleanup.rs`
`STALE_AFTER`. Item 4 (MUS-76) wasn't traced through upstream's
`codex_bridge.rs`. Check it before filing, or drop it. Item 3 was traced: the
WS branch of the sweep in `cleanup.rs` reaps on `STALE_AFTER` with no `WakeWatcher` check.
- Item 5 may be moot after #141. Leave it out if you'd rather keep the issue
short.
- Our versions: MUS-73 (empty `to`); MUS-72, 78 and 79 (first write); durability's
keep-alive; MUS-76 (Codex); inbox quoting (`port/inbox-quoting-2`).
33 changes: 15 additions & 18 deletions docs/upstream-pr-m2.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ Where it fits in the series is in [upstream-pr-strategy.md](upstream-pr-strategy

| | |
|---|---|
| Branch | `port/terminal-cmds` at `5044c3e` (Castor-o7/muster, by peppy-skate, review fixes by bright-roller), on `62552e6`, #164's head. Pushed to Castor-o7/marshal when it's sent |
| Contents | 3 commits, 6 files, +660 −14. `100d7ea`: the terminal commands (Muster's `9fdf775`) without `idempotency_key`, which arrives with Durability. `da4b719`: the plugin README fix (Muster's `abb4c94`). `5044c3e`: the review fixes (the roster's `recorded` wording, the too-short refusal, and tests for the label and the per-recipient lines) |
| Opens | after #164 merges, since the roster's `wake` field comes from #164 |
| Checked | at `5044c3e` on Murph: workspace tests (205) green, `clippy --workspace --all-targets -D warnings` and `fmt` clean, and the Muster-name grep finds 0 (bright-roller). At `da4b719`, the sandbox unittest passed too (peppy-skate). It rebases cleanly onto #164's evidence and comment commits, since it doesn't touch those files |
| Branch | **`port/terminal-cmds-v3` at `3af92d7`** on Castor-o7/marshal (ultra-dune, 2026-11-05): one commit on upstream `9b00c6f` (v0.58.0), cherry-picked from `481f18a`, `2211da4` and `4a53e00`. It replaces the older `port/terminal-cmds` cut (`5044c3e` on `62552e6`) |
| Contents | 1 commit, 5 files, +663 −9: `crates/shim/src/terminal_send.rs`, `roster_read.rs`, `main.rs` (subcommands and `usage()`), `README.md`, and `plugins/marshal-shim/README.md` |
| Checked | at `3af92d7`: a clean clone passes 257/0 for daemon, shim and entities; clippy and fmt are clean; native Windows is green (Castor-o7/marshal run 42114245402, windows-native-wake); there are no Muster names. The lamplighter re-verified the branch, diff and log |

---

Expand Down Expand Up @@ -58,12 +57,9 @@ a Marshal user who doesn't run them sees no change.
in `<project>/.mcp.json`, with the status line and the hooks in
`settings.json`. The README also said sessions have no nickname; they do,
and peers can be addressed by nickname or `session_id`.
- **Internal tidy-up:** the shim's address lookup moves into one
`daemon_address()` that the three myko paths share (the MCP server, terminal
send and the roster), and `tools::await_command` becomes `pub(crate)`.
The statusline's reachability check keeps its own lookup in `channels.rs`,
which reads the environment first and has no default, so an unconfigured
machine isn't warned. Behaviour is unchanged.
- **`--help`:** `marshal-shim --help` lists `tell`, `all` and `roster`. Both
new paths reach the daemon through the shim's existing `daemon_address()`, so
nothing else in the shim changes.

## What changes by default

Expand All @@ -73,11 +69,9 @@ removed. Sessions see the labelled message like any other direct mail.

## Overlaps

- **#135 (lobo235)** adds `--help` and `--version` to the daemon, shim and
TUI, and edits the same argument match in `shim/src/main.rs`. The two don't
conflict in intent. Whichever lands second takes the other's arms, and we're
happy to rebase onto #135.
- **Depends on #164**, whose roster `wake` field this prints.
- Built on `main` at v0.58.0, so it already includes #135's `--help`/`--version`:
`tell`, `all` and `roster` are added to the shim's `usage()` text.
- Uses the roster `wake` field that #164 added.

## Evidence

Expand All @@ -88,9 +82,12 @@ removed. Sessions see the labelled message like any other direct mail.
- 1 checks the label.
- 2 check the line printed for each recipient: each send outcome, a failed
send, and a recipient with no team, host or stored nickname.
- On this exact head: a clean clone passes
`cargo test -p marshal-daemon -p marshal-shim -p marshal-entities` (257 passed,
0 failed); `clippy -D warnings` and `fmt` are clean; native Windows CI is green on
the fork. No version bump.
- The same commands have run in Muster, a fork of Marshal, since 2026-11-03.
Operators message every session from a terminal with them, and scripts read
the roster.
- **Zoo:** not needed. Nothing agent-facing changes unless someone runs the
commands, and a terminal message is ordinary direct mail with a label. The
operator can ask for a run if upstream wants one.
- **Zoo:** not run. Nothing agent-facing changes unless someone runs the
commands, and a terminal message is ordinary direct mail with a label.
Loading
Loading