Summary
Make CLI commands and executable scripts first-class outputs of the Agent Bundle
compiler. Projects may author a custom CLI tree, generate CLI commands from MCP
routes through MCPorter, ship ordinary scripts, and ship React-rendered scripts.
All modes use the existing Rslib build path and the same compiled route graph as
MCP and Workbench.
Generated CLI commands and rendered scripts enter through the same typed Agent
request context as MCP and event routes. Plain scripts remain ordinary Node
programs unless their extension and route contract explicitly opt into Agent
Document rendering.
Existing capabilities to preserve
src/cli.ts is already a conventional package bin entry.
src/index.ts is already a conventional library entry.
- configured scripts already compile into host artifacts.
- generated executable shells already support shebangs and self-contained
Rslib output.
- framework builds already validate and track source provenance.
This issue removes remaining manual dispatch and adds compiler-generated
projections; it does not create a second packaging system.
Goals
- Support a custom filesystem-routed CLI root.
- Optionally expose compiled MCP tools as CLI commands through MCPorter.
- Merge custom and generated commands into one coherent product CLI.
- Support plain JS/TS scripts without forcing them into the React renderer.
- Support JSX/TSX scripts whose output uses the Agent Document renderer.
- Provide deterministic streaming and machine-readable output modes.
- Detect command collisions and unsupported projections during compilation.
Proposed configuration
export default defineConfig({
cli: {
mcpPorter: true,
},
});
The exact spelling can change during API review. The semantics are:
src/cli/* is discovered automatically when present;
cli.mcpPorter projects eligible local MCP tools into the same CLI tree;
src/scripts/* is discovered automatically when present;
- custom roots are optional overrides, not required setup;
- explicit command/script declarations override conventional paths;
- compiler diagnostics report uncovered, shadowed, or conflicting files.
Custom CLI routes
src/cli/
doctor.tsx
cache/
clear.ts
config/
show.tsx
Each route exports its parser/schema and default handler or component:
export const config = {
description: 'Inspect the generated Agent Bundle runtime.',
aliases: ['health'],
} satisfies CliRouteConfig;
export const input = z.object({
verbose: z.boolean().default(false),
});
export default async function Doctor({ input }: CliRouteProps<typeof input>) {
const health = await inspectHealth(input);
return <Agent.Json value={health} />;
}
The compiler generates:
- command names and nesting from paths;
- help and typed argument parsing;
- lazy command imports where appropriate;
- final exit-code and error mapping;
- one Rslib-built executable;
- the route types used by tests and Workbench.
The command path supplies identity. An optional named config export supplies
descriptions, aliases, visibility, and safety metadata. There is no per-command
sidecar config file or duplicate command declaration in
agent-bundle.config.ts; the root config only supplies project-wide CLI roots,
defaults, policies, and explicit overrides.
MCPorter projection
MCPorter can generate a standalone CLI
from an MCP server. Agent Bundle should integrate that capability at compile
time from its already-validated MCP route manifest rather than rediscovering a
running server during every build.
Recommended behavior when mcpPorter: true:
- Select local generated MCP servers and tools eligible for CLI exposure.
- Generate MCP-backed command definitions from the compiled tool schemas and
listing metadata.
- Merge those definitions with custom CLI routes.
- Fail the build when custom and generated commands claim the same command
path unless config explicitly resolves the conflict.
- Preserve one executable, one help tree, and one version/identity surface.
- Record the MCP route that generated each command in artifact provenance.
Configuration may include bounded inclusion/exclusion:
cli: {
mcpPorter: {
include: ['curator:*'],
exclude: ['curator:apply_*'],
},
},
Mutation-capable MCP tools must retain their safety semantics in CLI help and
must not become less guarded merely because they are callable from a shell.
The generated CLI preserves the route's authorization and confirmation policy;
when the original surface requires interactive consent and no equivalent CLI
confirmation/authorization channel exists, invocation fails closed.
Script conventions
src/scripts/
rebuild-index.ts
summarize-library.tsx
export-report.js
render-release-notes.jsx
Behavior by extension:
.js, .mjs, .ts, .mts: ordinary executable entry. The framework
supplies compilation, packaging, cancellation, and provenance but does not
reinterpret its stdout.
.jsx, .tsx: rendered script entry. The default export is executed through
the Agent Document renderer and supports Markdown, JSON, progress, resources,
Suspense, and final output modes.
Rendered script example:
export const config = {
description: 'Summarize the configured audiobook library.',
} satisfies RenderedScriptConfig;
export default async function SummarizeLibrary({ argv, signal }: ScriptProps) {
const summary = await summarize(argv, { signal });
return (
<Agent.Result value={summary}>
<Agent.Markdown>
Found **{summary.books}** books across **{summary.roots}** roots.
</Agent.Markdown>
</Agent.Result>
);
}
Ordinary scripts remain useful for maintenance helpers that do not need
agent-facing rendering. The file extension is an explicit, visible contract;
the framework must not silently wrap a plain script in React behavior.
Output contract
Every rendered CLI command or TSX/JSX script supports:
text or markdown: human/agent-readable final output;
json: one canonical final JSON document;
ndjson: sequence-numbered render events;
- interactive TTY progress;
- quiet/final-only operation.
Plain scripts retain normal Node stdout/stderr semantics.
NDJSON render events are an Agent Bundle CLI/script output dialect, not MCP
JSON-RPC or partial tool-result streaming. They must never be written as
non-MCP bytes to an MCP server's stdout.
Rules:
- rendered machine output uses stdout;
- logs and diagnostics use stderr;
- partial fallbacks are never left in final piped Markdown;
SIGINT/SIGTERM reach the framework AbortSignal;
- exit codes are deterministic and declared per route or derived from the final
Agent Result status;
- secrets and credentials are never synthesized into command arguments or
artifact manifests.
Generated build model
The meta-framework compiler emits:
- a custom CLI route manifest;
- an MCPorter-generated command manifest;
- a collision-resolved combined command graph;
- ordinary script Rslib entries;
- rendered-script entries bound to the Agent renderer;
- generated help, types, and test fixtures;
- host artifact script declarations.
The generated command graph is inspected by agent-bundle inspect and the
Workbench. The same graph drives completion/help generation and Rstest.
Migration
- Keep
src/cli.ts and explicit scripts entries working.
- Add zero-config filesystem CLI/script discovery with explicit override and
disable controls.
- Generate a CLI for one reference MCP server using MCPorter.
- Merge generated and custom commands with collision diagnostics.
- Migrate Audiobook Curator's manual CLI operation registry.
- Update scaffolder templates.
- Deprecate manual framework dispatch while retaining explicit raw entries as
an escape hatch.
Acceptance criteria
- One project ships custom commands, MCP-generated commands, plain scripts, and
rendered scripts through one Agent Bundle build.
- Help, types, schemas, Workbench catalog, and packed executable agree on the
command graph.
- A generated MCP command invokes the same route contract as the MCP tool.
- When an MCP-generated command uses the wire rather than direct local route
invocation, it preserves negotiated progress/task support and the distinct
ordinary-request versus task cancellation/result flows.
- A custom command can use the Agent renderer without becoming an MCP tool.
- A plain script remains a normal executable with no renderer assumptions.
- Command collisions fail at build time with actionable diagnostics.
- Mutation-capable projections preserve authorization/confirmation behavior or
fail closed; help text alone is not treated as protection.
- TTY, Markdown, JSON, and NDJSON output have direct Rstest and packed-artifact
coverage.
Design references
Stack position
Full meta-framework stack
Summary
Make CLI commands and executable scripts first-class outputs of the Agent Bundle
compiler. Projects may author a custom CLI tree, generate CLI commands from MCP
routes through MCPorter, ship ordinary scripts, and ship React-rendered scripts.
All modes use the existing Rslib build path and the same compiled route graph as
MCP and Workbench.
Generated CLI commands and rendered scripts enter through the same typed Agent
request context as MCP and event routes. Plain scripts remain ordinary Node
programs unless their extension and route contract explicitly opt into Agent
Document rendering.
Existing capabilities to preserve
src/cli.tsis already a conventional package bin entry.src/index.tsis already a conventional library entry.Rslib output.
This issue removes remaining manual dispatch and adds compiler-generated
projections; it does not create a second packaging system.
Goals
Proposed configuration
The exact spelling can change during API review. The semantics are:
src/cli/*is discovered automatically when present;cli.mcpPorterprojects eligible local MCP tools into the same CLI tree;src/scripts/*is discovered automatically when present;Custom CLI routes
Each route exports its parser/schema and default handler or component:
The compiler generates:
The command path supplies identity. An optional named
configexport suppliesdescriptions, aliases, visibility, and safety metadata. There is no per-command
sidecar config file or duplicate command declaration in
agent-bundle.config.ts; the root config only supplies project-wide CLI roots,defaults, policies, and explicit overrides.
MCPorter projection
MCPorter can generate a standalone CLI
from an MCP server. Agent Bundle should integrate that capability at compile
time from its already-validated MCP route manifest rather than rediscovering a
running server during every build.
Recommended behavior when
mcpPorter: true:listing metadata.
path unless config explicitly resolves the conflict.
Configuration may include bounded inclusion/exclusion:
Mutation-capable MCP tools must retain their safety semantics in CLI help and
must not become less guarded merely because they are callable from a shell.
The generated CLI preserves the route's authorization and confirmation policy;
when the original surface requires interactive consent and no equivalent CLI
confirmation/authorization channel exists, invocation fails closed.
Script conventions
Behavior by extension:
.js,.mjs,.ts,.mts: ordinary executable entry. The frameworksupplies compilation, packaging, cancellation, and provenance but does not
reinterpret its stdout.
.jsx,.tsx: rendered script entry. The default export is executed throughthe Agent Document renderer and supports Markdown, JSON, progress, resources,
Suspense, and final output modes.
Rendered script example:
Ordinary scripts remain useful for maintenance helpers that do not need
agent-facing rendering. The file extension is an explicit, visible contract;
the framework must not silently wrap a plain script in React behavior.
Output contract
Every rendered CLI command or TSX/JSX script supports:
textormarkdown: human/agent-readable final output;json: one canonical final JSON document;ndjson: sequence-numbered render events;Plain scripts retain normal Node stdout/stderr semantics.
NDJSON render events are an Agent Bundle CLI/script output dialect, not MCP
JSON-RPC or partial tool-result streaming. They must never be written as
non-MCP bytes to an MCP server's stdout.
Rules:
SIGINT/SIGTERMreach the frameworkAbortSignal;Agent Result status;
artifact manifests.
Generated build model
The meta-framework compiler emits:
The generated command graph is inspected by
agent-bundle inspectand theWorkbench. The same graph drives completion/help generation and Rstest.
Migration
src/cli.tsand explicitscriptsentries working.disable controls.
an escape hatch.
Acceptance criteria
rendered scripts through one Agent Bundle build.
command graph.
invocation, it preserves negotiated progress/task support and the distinct
ordinary-request versus task cancellation/result flows.
fail closed; help text alone is not treated as protection.
coverage.
Design references
Stack position
Full meta-framework stack