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
40 changes: 29 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Reference runtime for the Multi-Agent Coordination Protocol (MACP).

This runtime implements the current MACP core/service surface and all six standards-track modes in the main RFC repository. The focus of this release is freeze-readiness for SDKs and real-world unary and streaming integrations: strict `SessionStart`, mode-semantic correctness, authenticated senders, bounded resources, and durable restart recovery.
This runtime implements the current MACP core/service surface, five standards-track modes, and one built-in extension mode. The focus of this release is freeze-readiness for SDKs and real-world unary and streaming integrations: strict `SessionStart`, mode-semantic correctness, authenticated senders, bounded resources, durable restart recovery, and extension mode lifecycle management.

## What changed in v0.4.0

Expand Down Expand Up @@ -40,7 +40,14 @@ This runtime implements the current MACP core/service surface and all six standa
- **StreamSession enabled**
- `Initialize` advertises `stream: true`
- `StreamSession` provides per-session bidirectional streaming of accepted envelopes
- `WatchModeRegistry` and `WatchRoots` implemented (basic: send initial state, hold stream open)
- `WatchModeRegistry` fires live `RegistryChanged` events on mode register/unregister/promote
- `WatchRoots` implemented (basic: send initial state, hold stream open)
- **Extension mode lifecycle**
- `multi_round` demoted from standards-track to built-in extension (`ext.multi_round.v1`)
- `ListExtModes` returns extension mode descriptors
- `RegisterExtMode` dynamically registers new extension modes with a passthrough handler
- `UnregisterExtMode` removes dynamically registered extensions (built-in modes protected)
- `PromoteMode` promotes extensions to standards-track with optional identifier rename
- **Structured logging via `tracing`**
- use `RUST_LOG` env var to control log level (e.g. `RUST_LOG=info`)
- **Per-mode metrics**
Expand All @@ -55,13 +62,16 @@ Standards-track modes:
- `macp.mode.task.v1`
- `macp.mode.handoff.v1`
- `macp.mode.quorum.v1`
- `macp.mode.multi_round.v1`

Built-in extension modes:

- `ext.multi_round.v1`

## Runtime behavior that SDKs should assume

### Session bootstrap

For all six standards-track modes, `SessionStartPayload` must include:
For all standards-track modes and built-in extensions, `SessionStartPayload` must include:

- `participants`
- `mode_version`
Expand Down Expand Up @@ -191,6 +201,10 @@ cargo run --bin fuzz_client
| `StreamSession` | implemented |
| `WatchModeRegistry` | implemented |
| `WatchRoots` | implemented |
| `ListExtModes` | implemented |
| `RegisterExtMode` | implemented |
| `UnregisterExtMode` | implemented |
| `PromoteMode` | implemented |

## Architecture

Expand All @@ -203,8 +217,9 @@ Client Request
|
[Mode Registry] -- mode_registry.rs
| \
[Mode Logic] [Discovery]
mode/*.rs ListModes, GetManifest
[Mode Logic] [Discovery + Extension Lifecycle]
mode/*.rs ListModes, ListExtModes, GetManifest,
RegisterExtMode, UnregisterExtMode, PromoteMode
|
[Storage Layer] -- storage.rs, log_store.rs
|
Expand All @@ -230,11 +245,13 @@ runtime/
│ ├── storage.rs # storage backend trait, FileBackend, crash recovery
│ ├── replay.rs # session rebuild from append-only log
│ ├── metrics.rs # per-mode metrics counters
│ ├── mode/ # mode implementations
│ ├── mode/ # mode implementations (standards-track + extensions)
│ │ ├── passthrough.rs # generic handler for dynamically registered extensions
│ │ └── ...
│ └── bin/ # local development example clients
├── tests/
│ ├── integration_mode_lifecycle.rs # full-stack integration tests
│ ├── replay_round_trip.rs # replay tests for all 6 modes
│ ├── replay_round_trip.rs # replay tests for all modes
│ ├── conformance_loader.rs # JSON fixture runner
│ └── conformance/ # per-mode conformance fixtures
├── docs/
Expand All @@ -250,7 +267,7 @@ Set `MACP_ALLOW_INSECURE=1` for local development, or provide `MACP_TLS_CERT_PAT
Session IDs must be UUID v4/v7 in hyphenated lowercase form (36 chars) or base64url tokens (22+ chars). Short or human-readable IDs like `"s1"` or `"my-session"` are rejected.

**`InvalidPayload` on `SessionStart`**
For standards-track modes, `SessionStartPayload` must include non-empty `participants`, `mode_version`, `configuration_version`, and a positive `ttl_ms`. Empty payloads are rejected.
For standards-track modes and built-in extensions (including `ext.multi_round.v1`), `SessionStartPayload` must include non-empty `participants`, `mode_version`, `configuration_version`, and a positive `ttl_ms`. Empty payloads are rejected.

**`Forbidden` error**
Check that the sender identity matches the session's participant list. For `Commitment` messages, only the session initiator is authorized. Verify your bearer token maps to the correct sender.
Expand All @@ -264,8 +281,9 @@ Run `make sync-protos` to update local proto files from BSR.
## Development notes

- The RFC/spec repository remains the normative source for protocol semantics.
- This runtime only accepts the canonical standards-track mode identifiers for all six modes.
- `multi_round` is now standards-track and is advertised by discovery RPCs.
- Five standards-track modes use the canonical `macp.mode.*` identifiers.
- `multi_round` is a built-in extension (`ext.multi_round.v1`) — not standards-track, but ships with the runtime and enforces strict `SessionStart`.
- Extension modes can be dynamically registered, unregistered, and promoted via `RegisterExtMode`, `UnregisterExtMode`, and `PromoteMode` RPCs.
- `StreamSession` is enabled and binds one gRPC stream to one session, emitting accepted envelopes in order.

See `docs/README.md` and `docs/examples.md` for the updated local development and usage guidance.
23 changes: 17 additions & 6 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ The RFC/spec repository is still the normative source for MACP semantics. These
## What is in this runtime profile

- MACP server over gRPC with unary RPCs and per-session bidirectional streaming
- six standards-track modes from the main RFC repository
- strict canonical `SessionStart` for standards-track modes
- five standards-track modes from the main RFC repository and one built-in extension
- strict canonical `SessionStart` for standards-track modes and qualifying extensions
- authenticated sender derivation
- payload limits and rate limiting
- optional file-backed persistence for sessions and accepted-history logs
- extension mode lifecycle management (register, unregister, promote)

## Standards-track modes

Expand All @@ -20,7 +21,10 @@ The RFC/spec repository is still the normative source for MACP semantics. These
- `macp.mode.task.v1`
- `macp.mode.handoff.v1`
- `macp.mode.quorum.v1`
- `macp.mode.multi_round.v1`

## Built-in extension modes

- `ext.multi_round.v1`

## Freeze profile

Expand All @@ -37,10 +41,17 @@ Implemented and supported:
- `ListModes`
- `ListRoots`

Streaming watch RPCs (basic — send initial state, hold stream open):
Extension mode lifecycle:

- `ListExtModes`
- `RegisterExtMode`
- `UnregisterExtMode`
- `PromoteMode`

Streaming watch RPCs:

- `WatchModeRegistry`
- `WatchRoots`
- `WatchModeRegistry` — sends initial state, then fires on register/unregister/promote changes
- `WatchRoots` — sends initial state, holds stream open

## Security model

Expand Down
20 changes: 15 additions & 5 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,20 @@ Responsibilities:
- provide standards-track mode names for `ListModes`
- provide mode descriptors for `ListModes` and `GetManifest`

The registry uses `RwLock` for thread-safe dynamic mode registration.

Key methods:

- `build_default()` — constructs the canonical mode set
- `build_default()` — constructs the canonical mode set (5 standards-track + 1 built-in extension)
- `get_mode(name)` — mode lookup for dispatch
- `standard_mode_names()` — drives `ListModes` and `GetManifest`
- `standard_mode_names()` — drives `ListModes`
- `standard_mode_descriptors()` — drives `ListModes` response
- `all_mode_names()` — drives `GetManifest` and `Initialize` (all modes)
- `extension_mode_descriptors()` — drives `ListExtModes`
- `register_extension(descriptor)` — dynamic extension registration
- `unregister_extension(mode)` — dynamic extension removal (built-in modes cannot be removed)
- `promote_mode(mode, new_name)` — promote extension to standards-track
- `subscribe_changes()` — broadcast channel for `WatchModeRegistry`

## 4. Mode layer (`src/mode/*`)

Expand All @@ -57,7 +65,8 @@ Implemented modes:
- Task — delegated task with serial assignment, progress tracking, terminal reports
- Handoff — serial handoff offers with accept/decline disposition
- Quorum — threshold approval with ballots
- MultiRound — iterative value convergence with explicit Commitment
- MultiRound (`ext.multi_round.v1`) — built-in extension: iterative value convergence with explicit Commitment
- PassthroughMode — generic handler for dynamically registered extension modes

## 5. Storage layer

Expand Down Expand Up @@ -110,8 +119,9 @@ Client Request
|
[Mode Registry] -- mode_registry.rs
| \
[Mode Logic] [Discovery]
mode/*.rs ListModes, GetManifest
[Mode Logic] [Discovery + Extension Lifecycle]
mode/*.rs ListModes, ListExtModes, GetManifest,
RegisterExtMode, UnregisterExtMode, PromoteMode
|
[Storage Layer] -- storage.rs, log_store.rs
|
Expand Down
36 changes: 26 additions & 10 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ cargo run

The example binaries in `src/bin` attach `x-macp-agent-id` metadata so the runtime can derive the authenticated sender.

## Ground rules for every standards-track session
## Ground rules for sessions with strict validation

For these modes:
For these standards-track modes and built-in extensions:

- `macp.mode.decision.v1`
- `macp.mode.proposal.v1`
- `macp.mode.task.v1`
- `macp.mode.handoff.v1`
- `macp.mode.quorum.v1`
- `macp.mode.multi_round.v1`
- `ext.multi_round.v1` (built-in extension)

`SessionStartPayload` must include all of the following:

Expand Down Expand Up @@ -132,7 +132,7 @@ Flow:
3. participants send ballots
4. coordinator emits `Commitment` after threshold is satisfied

## Example 6: Multi-round mode
## Example 6: Multi-round mode (built-in extension)

Run:

Expand All @@ -142,16 +142,16 @@ cargo run --bin multi_round_client

Flow:

1. coordinator starts the session with strict `SessionStart` (participants, mode_version, configuration_version, ttl_ms)
2. participants exchange proposals across multiple rounds
1. coordinator starts the session with mode `ext.multi_round.v1` and strict `SessionStart` (participants, mode_version, configuration_version, ttl_ms)
2. participants exchange contributions across multiple rounds
3. convergence is tracked by the runtime
4. coordinator emits `Commitment` after convergence

Important runtime behavior:

- `macp.mode.multi_round.v1` is a standards-track mode and is advertised by discovery RPCs
- `ext.multi_round.v1` is a built-in extension mode, discoverable via `ListExtModes`
- convergence is tracked but does not auto-resolve the session — an explicit `Commitment` is required
- uses the same strict `SessionStart` contract as all other standards-track modes
- uses the same strict `SessionStart` contract as standards-track modes

## Example 7: StreamSession

Expand All @@ -167,7 +167,23 @@ Practical notes:
- use a session-scoped `Signal` envelope with the correct `session_id` and `mode` to attach to an existing session without mutating it
- mixed-session streams are rejected with `FAILED_PRECONDITION`

## Example 8: Freeze-check / error-path client
## Example 8: Extension mode lifecycle

The runtime supports dynamic extension mode management via gRPC:

1. **`ListExtModes`** — discover available extension modes (e.g. `ext.multi_round.v1`)
2. **`RegisterExtMode`** — register a new extension mode by providing a `ModeDescriptor` with the mode name, message types, and terminal message types; the runtime creates a passthrough handler
3. **`UnregisterExtMode`** — remove a dynamically registered extension (built-in modes like `ext.multi_round.v1` cannot be removed)
4. **`PromoteMode`** — promote an extension to standards-track, optionally renaming the identifier (e.g. `ext.foo.v1` to `macp.mode.foo.v1`)

Important runtime behavior:

- extension mode names must not use the reserved `macp.mode.*` namespace
- dynamically registered modes use a passthrough handler that accepts any listed message type and requires explicit `Commitment` from the initiator to resolve
- `WatchModeRegistry` subscribers receive `RegistryChanged` events on every register, unregister, or promote operation
- `GetManifest` and `Initialize` always include all modes (standards-track + extensions); `ListModes` only returns standards-track

## Example 9: Freeze-check / error-path client

Run:

Expand Down Expand Up @@ -208,7 +224,7 @@ and ensure the client sets `x-macp-agent-id`.

### `INVALID_ENVELOPE` on `SessionStart`

For a standards-track mode, check that:
For a standards-track mode or built-in extension, check that:

- the mode name is canonical
- the payload is not empty
Expand Down
25 changes: 18 additions & 7 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,23 @@ Clients should call `Initialize` before using the runtime.
- `ListRoots`
- `WatchModeRegistry`
- `WatchRoots`
- `ListExtModes`
- `RegisterExtMode`
- `UnregisterExtMode`
- `PromoteMode`

## Streaming watch RPCs

- `WatchModeRegistry` — sends the current registry state, then holds the stream open
- `WatchModeRegistry` — sends the current registry state, then fires `RegistryChanged` on register/unregister/promote
- `WatchRoots` — sends the current roots state, then holds the stream open

## Extension mode lifecycle RPCs

- `ListExtModes` — returns `ModeDescriptor` entries for all extension modes
- `RegisterExtMode` — registers a new extension mode from a `ModeDescriptor`; the runtime creates a passthrough handler that accepts message types listed in the descriptor and requires explicit `Commitment` to resolve
- `UnregisterExtMode` — removes a dynamically registered extension; built-in and standards-track modes cannot be removed
- `PromoteMode` — promotes an extension to standards-track; optionally renames the mode identifier (e.g. `ext.foo.v1` to `macp.mode.foo.v1`)

## StreamSession profile

`StreamSession` is session-scoped and authoritative for accepted envelopes:
Expand All @@ -40,16 +51,16 @@ Clients should call `Initialize` before using the runtime.
- stream-level validation failures terminate the stream with a gRPC status; use `Send` if you need explicit per-message negative acknowledgements
- to attach to an existing session without mutating it, send a session-scoped `Signal` envelope with the correct `session_id` and `mode`

## Standards-track mode rules
## Strict session start rules

For these modes:
For these standards-track modes and built-in extensions:

- `macp.mode.decision.v1`
- `macp.mode.proposal.v1`
- `macp.mode.task.v1`
- `macp.mode.handoff.v1`
- `macp.mode.quorum.v1`
- `macp.mode.multi_round.v1`
- `ext.multi_round.v1` (built-in extension)

`SessionStartPayload` must bind:

Expand All @@ -62,7 +73,7 @@ Empty payloads are rejected. Empty `mode` values are rejected. Duplicate partici

## Multi-round mode

`macp.mode.multi_round.v1` is a standards-track mode. It uses the same strict `SessionStart` contract as all other standards-track modes. Convergence is tracked but does not auto-resolve the session — an explicit `Commitment` is required after convergence.
`ext.multi_round.v1` is a built-in extension mode. It uses the same strict `SessionStart` contract as standards-track modes. Convergence is tracked but does not auto-resolve the session — an explicit `Commitment` is required after convergence.

## Security profile

Expand Down Expand Up @@ -92,8 +103,8 @@ This gives restart recovery for session metadata, dedup state, and accepted-hist

## Commitment validation

For standards-track modes, `CommitmentPayload` must carry version fields that match the session-bound values.
For standards-track modes and built-in extensions, `CommitmentPayload` must carry version fields that match the session-bound values. Dynamically registered extension modes use a passthrough handler that also validates commitment version fields.

## Discovery notes

`ListModes` returns all six standards-track modes. `GetManifest` exposes a manifest that matches the implemented unary and streaming capabilities.
`ListModes` returns five standards-track modes. `ListExtModes` returns extension mode descriptors. `GetManifest` exposes all supported modes (standards-track + extensions). `RegisterExtMode`, `UnregisterExtMode`, and `PromoteMode` manage extension lifecycle at runtime.
Loading
Loading