Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a43bad4
Add result flow paging contracts
carldebilly May 4, 2026
96fde43
Render paged results in core formats
carldebilly May 4, 2026
fc09600
Add MCP and Spectre paged result support
carldebilly May 4, 2026
9fdc803
Add interactive result pager
carldebilly May 4, 2026
90af4e8
Document result flow paging
carldebilly May 4, 2026
c05fb64
Add result flow paging demos
carldebilly May 4, 2026
017e05c
Add safer page source helpers
carldebilly May 5, 2026
95d5ce2
Harden MCP paged result handling
carldebilly May 5, 2026
0c533d3
Fix result pager boundary navigation
carldebilly May 5, 2026
f330ca2
Wire page sources through result flow
carldebilly May 5, 2026
2ef32da
Add scroll viewport result pager
carldebilly May 5, 2026
2b6497a
Tighten result flow contracts
carldebilly May 5, 2026
3927f2a
Document replayable async page sources
carldebilly May 5, 2026
955b252
Validate MCP result cursors
carldebilly May 5, 2026
2d85147
Harden scroll pager rendering
carldebilly May 5, 2026
8df04a4
Avoid repeated markdown page allocations
carldebilly May 5, 2026
d1e1253
Address paging edge cases
carldebilly May 5, 2026
2c770b8
fix(result-flow): tighten scroll pager key handling and doc perf
carldebilly May 5, 2026
cf89dea
refactor(result-flow): style polish
carldebilly May 5, 2026
05605aa
Address review comments
carldebilly May 5, 2026
dc0b815
Fix review and documentation lint issues
carldebilly May 6, 2026
6578ce1
Smooth result flow scroll pager
carldebilly May 6, 2026
e68bd7f
Handle scroll pager viewport changes
carldebilly May 6, 2026
3ec8246
Harden scroll pager terminal rendering
carldebilly May 6, 2026
44611a8
Refactor result flow pager modes
carldebilly May 6, 2026
e2e61d7
Fix more pager ignored key output
carldebilly May 6, 2026
621c5e4
Skip repeated pager payload headers
carldebilly May 6, 2026
90d89f5
Render pager continuations without headers
carldebilly May 6, 2026
a099fb0
Extract terminal surface lifecycle for pager
carldebilly May 7, 2026
e82ec66
Clear more pager prompt in ANSI terminals
carldebilly May 7, 2026
1ec2c82
Continue more pager page down across payloads
carldebilly May 7, 2026
a0f8a2f
Document source versus output paging
carldebilly May 7, 2026
14b03be
Harden result-flow cursors
carldebilly May 8, 2026
74ef852
Refine paging public surface
carldebilly May 8, 2026
831e7bd
Harden terminal surface cleanup
carldebilly May 8, 2026
15decd3
Bound pager buffers and log fetch diagnostics
carldebilly May 8, 2026
69828c8
Separate pager payload state
carldebilly May 8, 2026
fb7d57a
Document complete result-flow paging
carldebilly May 8, 2026
0937f3f
Polish result-flow paging internals
carldebilly May 8, 2026
8a7f571
Harden result-flow paging review fixes
carldebilly May 9, 2026
38fb323
Update paging docs for MCP hardening
carldebilly May 9, 2026
bd8ff16
Harden MCP paging fallbacks
carldebilly May 9, 2026
e3fb48e
Harden paging review fixes
carldebilly May 9, 2026
d85020f
Optimize ANSI text parsing
carldebilly May 9, 2026
52b0a11
Address paging PR review nits
carldebilly May 9, 2026
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
6 changes: 6 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
- Built-in `markdown` (with `--markdown` alias via output alias map).
- Global format selectors: `--json`, `--xml`, `--yaml`, `--yml`, `--output:<format>`.
- Unknown format returns explicit error text and non-zero exit code.
- Result flow:
- `IReplPagingContext` lets handlers page at the data source.
- `ReplPage<T>` carries current-page data plus continuation metadata.
- Human/Spectre terminal output can use an integrated pager; redirected stdout remains pipe-friendly.
- MCP maps `_replCursor` and `_replPageSize` to structured paged tool results.
- Numeric parsing:
- Numeric culture is configurable via `ParsingOptions.NumericCulture` (`Invariant` default, `Current` optional).
- Integer literals support C-like forms: hexadecimal (`0xFF`), binary (`0b1010` or `1010b`), and `_` separators (`1_000_000`).
Expand Down Expand Up @@ -101,6 +106,7 @@ The toolkit provides two application entry points for different scenarios.
## Related docs

- Command reference: `docs/commands.md`
- Result flow and paging: `docs/result-flow.md`
- Parameter system: `docs/parameter-system.md`
- Shell completion: `docs/shell-completion.md`

Expand Down
30 changes: 30 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ These flags are parsed before route execution:
- `--no-interactive`
- `--no-logo`
- `--output:<format>`
- `--result:page-size <n>` / `--result:page-size=<n>`
- `--result:cursor <value>` / `--result:cursor=<value>`
- `--result:all`
- `--result:pager=auto|off|more|inline|full`
- output aliases mapped by `OutputOptions.Aliases` (defaults include `--json`, `--xml`, `--yaml`, `--yml`, `--markdown`)
- `--answer:<name>[=value]` for non-interactive prompt answers
- custom global options registered via `options.Parsing.AddGlobalOption<T>(...)`
Expand All @@ -29,6 +33,7 @@ Global parsing notes:
- option value syntaxes accepted by command parsing: `--name value`, `--name=value`, `--name:value`
- use `--` to stop option parsing and force remaining tokens to positional arguments
- response files are supported with `@file.rsp` (enabled by default); nested `@` expansion is not supported
- result-flow options are reserved by the framework and do not bind to handler business parameters

## Declaring command options

Expand Down Expand Up @@ -249,6 +254,7 @@ Handlers can return any type. The framework renders the return value through the
| `string` | Rendered as plain text |
| Object / anonymous type | Rendered as key-value pairs (human) or serialized (JSON/XML/YAML) |
| `IEnumerable<T>` | Rendered as a table (human) or collection (structured formats) |
| `ReplPage<T>` | Rendered as the current page plus `PageInfo`; JSON uses `{ items, pageInfo }` |
| `IReplResult` | Structured result with kind prefix (`Results.Ok`, `Error`, `NotFound`...) |
| `ReplNavigationResult` | Renders payload and navigates scope (`Results.NavigateUp`, `NavigateTo`) |
| `IExitResult` | Renders optional payload and sets process exit code (`Results.Exit`) |
Expand Down Expand Up @@ -294,6 +300,30 @@ Tuple semantics:
- null elements are silently skipped
- nested tuples are not flattened — use a flat tuple instead

## Paging large results

Handlers that may return large result sets can request `IReplPagingContext`:

```csharp
app.Map("contacts", async (IReplPagingContext paging, ContactStore store, CancellationToken ct) =>
{
var rows = await store.QueryAsync(paging.Cursor, paging.SuggestedPageSize, ct);
return paging.Page(rows.Items, rows.NextCursor, rows.TotalCount);
});
```

When human users should continue through later pages without rerunning the
command, return a page source:

```csharp
app.Map("contacts", (ContactStore store) =>
ReplPageSource.FromOffset<ContactRow>(
(offset, take, ct) => store.QueryAsync(offset, take, ct),
totalCount: store.Count));
```

Use this when the data source can page efficiently. See [Result Flow And Paging](result-flow.md) for CLI flags, pager behavior, MCP paging arguments, and output format details.

## Interactive prompts

Handlers can use `IReplInteractionChannel` for guided prompts, progress reporting, and user-facing feedback. Extension methods add enum prompts, numeric input, validated text, notices, warnings, problem summaries, and more.
Expand Down
17 changes: 17 additions & 0 deletions docs/configuration-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,27 @@ Accessed via `ReplOptions.Output`.
- `ColorizeStructuredInteractive` (`bool`, default: `true`) — Colorize JSON/XML in interactive mode.
- `PreferredWidth` (`int?`, default: `null`) — Preferred render width. `null` uses automatic detection.
- `FallbackWidth` (`int`, default: `120`) — Fallback width when the terminal is unavailable.
- `ResultFlow` (`ResultFlowOptions`) - Paging and large-result behavior.
- `JsonSerializerOptions` (`JsonSerializerOptions`, default: Web defaults + indented) — JSON serializer options.

Built-in transformers: `human`, `json`, `xml`, `yaml`, `markdown`.

### ResultFlowOptions

Accessed via `ReplOptions.Output.ResultFlow`.

- `DefaultPageSize` (`int`, default: `100`) - Page size used when no caller or terminal hint provides one.
- `MaxPageSize` (`int`, default: `1000`) - Maximum accepted page size.
- `ReservedVisibleRows` (`int`, default: `2`) - Rows reserved when computing terminal-visible data rows.
- `DefaultPagerMode` (`ReplPagerMode`, default: `Auto`) - Pager behavior for human formats.
- `PagerRenderers` (`IReadOnlyList<IReplPagerRenderer>`) - Custom interactive pager renderers keyed by pager mode.
- `MaxBufferedLines` (`int`, default: `10000`) - Maximum content lines buffered by interactive viewport pagers.
- `ProgrammaticMaxInlineBytes` (`int`, default: `65536`) - Reserved for programmatic inline payload policy.

Register custom pager renderers with `UsePagerRenderer(renderer)`. Use
`RemovePagerRenderer(mode)` or `ClearPagerRenderers()` to alter the configured
renderer set.

### OutputOptions Methods

- `AddTransformer(name, transformer)` — Register a custom output transformer.
Expand Down
8 changes: 8 additions & 0 deletions docs/mcp-agent-capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,14 @@ Not all MCP clients support sampling and elicitation. The table below lists agen

Check [mcp-availability.com](https://mcp-availability.com/) for the latest data. Support is expanding rapidly — design your commands to degrade gracefully so they work everywhere even when a capability is missing.

Paged Repl tools do not require a special MCP capability for the first page:
every client that can call tools receives a bounded result. Continuation is
better when the client preserves structured tool results, because the raw cursor
is carried in `StructuredContent.pageInfo.nextCursor`. For clients that mostly
consume text, configure `ReplMcpServerOptions.PagedResultTextMode` to choose
between compatibility (`SerializedJson`) and lower token cost (`SummaryOnly`).
See [Paged tool results](mcp-reference.md#paged-tool-results).

## Direct MCP interfaces vs IReplInteractionChannel

| | `IMcpSampling` / `IMcpElicitation` / `IMcpFeedback` | `IReplInteractionChannel` |
Expand Down
73 changes: 72 additions & 1 deletion docs/mcp-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ app.UseMcpServer(o => o.InteractivityMode = InteractivityMode.PrefillThenElicita

| Method | Where it goes | Use? |
|---|---|---|
| **Return value** | `CallToolResult.Content` (JSON) | **Yes.** Preferred for all data. |
| **Return value** | `CallToolResult.Content` and, for paged results, `StructuredContent` | **Yes.** Preferred for all data. |
| **`IReplInteractionChannel`** | MCP primitives (progress, prompts, user-facing notices/problems) | **Yes.** Portable feedback that also works outside MCP. |
| **`IMcpFeedback`** | MCP progress and logging/message notifications | **Yes.** MCP-specific feedback when you need direct control. |
| **`ReplSessionIO.Output`** | Session output | Advanced cases only. |
Expand All @@ -187,6 +187,74 @@ app.UseMcpServer(o => o.InteractivityMode = InteractivityMode.PrefillThenElicita

> **Why this matters:** Console-style writes blur the boundary between result data, progress, logs, and protocol traffic. In MCP, this ranges from confusing agent behavior to protocol corruption.

### Paged tool results

Paged MCP tool schemas include two reserved Repl result-flow inputs:

- `_replCursor`: opaque continuation cursor returned by a previous paged result.
- `_replPageSize`: requested page size.

These inputs are emitted only for commands that accept `IReplPagingContext` or
return a paged result. Other tools reject them like any undeclared MCP argument.

Handlers receive these values through `IReplPagingContext`, not as business parameters. A handler can return `ReplPage<T>`:

```csharp
app.Map("contacts", (IReplPagingContext paging, ContactStore store) =>
{
var page = store.Query(paging.Cursor, paging.SuggestedPageSize);
return paging.Page(page.Items, page.NextCursor, page.TotalCount);
}).ReadOnly();
```

MCP responses for `ReplPage<T>` include:

- `StructuredContent`: `{ "$type": "page", items, pageInfo }`
- `Content`: configurable text fallback for clients that do not use structured content

By default, `Content` contains compact serialized JSON so agents that ignore
`StructuredContent` can still see the first page and cursor. Applications can
choose a cheaper text fallback:

```csharp
app.UseMcpServer(o =>
{
o.PagedResultTextMode = McpPagedResultTextMode.SummaryOnly;
});
```

| `PagedResultTextMode` | `Content` behavior | Trade-off |
|---|---|---|
| `SerializedJson` (default) | Compact JSON page envelope | Best compatibility; higher token cost |
| `SummaryOnly` | Short summary; cursor value stays only in structured content | Lowest token cost; clients must read structured content to continue |
| `SummaryAndSerializedJson` | Summary plus compact JSON page envelope | Most verbose; useful for diagnostics and weak clients |

Repl accepts compact cursor tokens only: non-empty, at most 512 characters, no
whitespace, no control characters, and not starting with `-`. Page-size tokens
must be numeric and at most 10 characters before normal result-flow clamping is
applied. Tool-call arguments are validated against the generated MCP input
schema before Repl reconstructs CLI tokens. Undeclared keys are rejected instead
of being converted to `--{key}` options, and business argument values that start
with `--` are rejected because the downstream CLI parser treats those as option
tokens.

MCP paging continuation works best when the client preserves structured tool
content. When `PagedResultTextMode` includes serialized JSON, the text fallback
also contains the page envelope; when it is `SummaryOnly`, the raw cursor stays
only in `StructuredContent.pageInfo.nextCursor`.

| Agent/client behavior | Paging support | Repl fallback |
|---|---|---|
| Reads `StructuredContent` and can call the same tool again | Full continuation with `_replCursor` and `_replPageSize` | Not needed |
| Reads only `Content` text | Sees first-page JSON by default; can continue only if it can reuse the cursor text safely | Configure `SerializedJson` or `SummaryAndSerializedJson` for compatibility, `SummaryOnly` for token savings |
| Ignores custom/reserved input properties | First page still works | Tool returns bounded first page |
| Does not support structured content | First page still works through text fallback; automatic continuation depends on `PagedResultTextMode` | Keep `SerializedJson` for weak clients or expose a command-specific cursor option |

Applications should not rely on all agents supporting continuation equally.
For important workflows, include enough data in the first page summary for the
agent to decide whether it needs a follow-up call, and keep handlers safe when
only the first page is consumed.

`WriteProgressAsync` maps to MCP progress notifications. `WriteStatusAsync` maps to log messages (`level: info`). See [Progress](progress.md#mcp) for the centralized progress model across console, hosted sessions, Spectre, and MCP:

```csharp
Expand Down Expand Up @@ -249,6 +317,7 @@ app.UseMcpServer(o =>
o.ResourceFallbackToTools = false; // also expose resources as tools
o.PromptFallbackToTools = false; // also expose prompts as tools
o.DynamicToolCompatibility = DynamicToolCompatibilityMode.Disabled; // shim for weak clients
o.PagedResultTextMode = McpPagedResultTextMode.SerializedJson; // paged result text fallback
o.EnableApps = false; // usually auto-enabled by MCP App mappings
o.CommandFilter = cmd => true; // filter which commands become tools
o.Prompt("summarize", (string topic) => ...); // explicit prompt registration
Expand Down Expand Up @@ -332,6 +401,8 @@ Feature support varies across agents. Check [mcp-availability.com](https://mcp-a
| Feature | Claude Desktop | Claude Code | Codex | VS Code Copilot | Cursor | Continue |
|---|---|---|---|---|---|---|
| Tools | Yes | Yes | Yes | Yes | Yes | Yes |
| Paged tools, first page | Yes | Yes | Yes | Yes | Yes | Yes |
| Paged tools, automatic continuation | Depends on structured tool-result handling | Depends on structured tool-result handling | Depends on structured tool-result handling | Depends on structured tool-result handling | Depends on structured tool-result handling | Depends on structured tool-result handling |
| Resources | Yes | — | — | Yes | Yes | — |
| Prompts | Yes | — | — | Yes | — | Yes |
| Discovery (`list_changed`) | — | Yes | — | — | — | — |
Expand Down
9 changes: 9 additions & 0 deletions docs/output-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

The output system controls how command results are serialized and rendered to the user. It supports multiple built-in formats, custom transformers, ANSI detection, and banner rendering.

Large result flow and paging are documented separately in [Result Flow And Paging](result-flow.md).

## Format Selection Precedence

The active output format is resolved in this order:
Expand Down Expand Up @@ -102,7 +104,14 @@ The output width used for wrapping and table layout is resolved as:

In interactive mode, when ANSI is supported, JSON output is syntax-highlighted automatically. This applies only to the `json` format rendered to a terminal — redirected or non-ANSI output remains plain.

## Paging

Human terminal formats (`human` and `spectre`) can use the integrated result pager when rendered output exceeds the visible row capacity or a result-flow page source has more data. The pager is never used for redirected stdout, protocol passthrough, MCP/programmatic execution, or machine formats.

Paged handler results should return `ReplPage<T>` through `IReplPagingContext`. JSON serializes these as `{ items, pageInfo }`; human and Spectre formats render the current page plus continuation metadata.

## See Also

- [Configuration Reference](configuration-reference.md) — `OutputOptions` properties.
- [Execution Pipeline](execution-pipeline.md) — output formatting occurs at stage 11.
- [Result Flow And Paging](result-flow.md) - paging contracts, CLI flags, and MCP behavior.
Loading
Loading