Add either streaming output support or REPL mode to an existing scaffolded CLI
Skill project by expanding the matching template and applying the documented
source patches. Feature additions must preserve the generated runtime
conventions already present in the scaffold, including plain-text --help,
structured help, user-scoped runtime directories, Active Context support,
and accurate structured-help metadata for newly enabled features. When a
feature request also changes the generated skill's user-facing purpose or
positioning, route through the description stage before continuing with this
operation.
| Input | Required | Format | Default | Description |
|---|---|---|---|---|
feature |
Yes | stream or repl |
— | Which optional capability to add. |
project_path |
Yes | Directory path | — | Path to the existing scaffolded Skill project. |
project_pathmust already contain a scaffolded Rust CLI Skill created from this Skill package or an equivalent structure.- The project must include
Cargo.toml,SKILL.md,src/main.rs,src/lib.rs, andsrc/help.rs. - The Agent must be able to read templates from this Skill package and write files into the target project.
Before making any edits:
- Resolve
project_pathto an absolute path. - Confirm
Cargo.tomlandSKILL.mdexist at the project root. If either is missing, stop: this is not a valid Skill project. - Confirm
src/main.rs,src/lib.rs, andsrc/help.rsexist. If any are missing, stop and explain which scaffolded file is absent. - Validate
featureis exactlystreamorrepl. Reject any other value. - Detect existing features:
- If
feature == streamandsrc/stream.rsalready exists, stop and tell the user streaming is already present. - If
feature == replandsrc/repl.rsalready exists, stop and tell the user REPL is already present.
- If
- Read the target project's current
Cargo.toml,src/main.rs,src/lib.rs,src/help.rs,SKILL.md, andtests/cli_test.rsif it exists. - Identify the crate name from
[package].name; use the snake_case crate path already present insrc/main.rs. - Expand the matching template from this Skill package:
templates/stream.rs.tpl->src/stream.rstemplates/repl.rs.tpl->src/repl.rs
- Apply the code snippets below to the target files.
- If the project already has the other optional feature, keep exactly one
output-construction block inside
execute_runand place feature-specific branches immediately before the default one-shot serialization path. - Keep
--replas an early global branch before the normal command match. - Keep
--streamscoped to theruncommand's output path instead of changing help, context, or runtime-directory commands. - Preserve the existing
helpsubcommand plus any context/runtime-directory command surfaces already scaffolded into the project. - Keep
src/help.rssynchronized by updating the global option list andFeatureAvailabilityvalues for the newly enabled feature. - Keep capability-specific support files package-local to the generated project. Repository-owned CI workflows, release scripts, and release automation stay outside generated skill outputs.
- If the project already has the other optional feature, keep exactly one
output-construction block inside
- Run validation commands after the edits:
cargo buildcargo testcargo clippy -- -D warningscargo fmt --check
- If validation fails, fix the generated code before reporting success.
- Expand
templates/stream.rs.tpltosrc/stream.rs. - Add the
--streamflag and dispatch branch tosrc/main.rs. - Add
pub mod stream;tosrc/lib.rs. - Update
src/help.rsso the global option list includes--streamand eachFeatureAvailabilityblock marks streaming as enabled. - Update
SKILL.mdso theOutputsection documents streaming behavior and the unsupported TOML case.
#[derive(Parser, Debug)]
#[command(
name = "<skill-name>",
version,
about = "<description>",
disable_help_flag = true,
disable_help_subcommand = true
)]
struct Cli {
...
+
+ /// Emit run-command records incrementally using the selected streaming protocol
+ #[arg(long, global = true)]
+ stream: bool,
}
fn run_cli() -> std::result::Result<(), AppExit> {
...
let runtime_overrides = cli_runtime_overrides(&cli);
+ let stream = cli.stream;
match cli.command {
None => render_plain_text_help_for_path(&[]),
Some(Command::Help(command)) => render_structured_help(&command.path, format),
- Some(Command::Run(command)) => execute_run(runtime_overrides, command, format),
+ Some(Command::Run(command)) => execute_run(runtime_overrides, command, format, stream),
Some(Command::Paths(command)) => execute_paths(runtime_overrides, command, format),
Some(Command::Context(command)) => execute_context(runtime_overrides, command, format),
}
}
fn execute_run(
overrides: RuntimeOverrides,
command: RunCommand,
format: Format,
+ stream: bool,
) -> std::result::Result<(), AppExit> {
...
let output = RunResponse { ... };
+ if stream {
+ return <crate_name>::stream::stream_value(&output, format).map_err(AppExit::from);
+ }
+
let stdout = std::io::stdout();
let mut stdout = stdout.lock();
serialize_value(&mut stdout, &output, format).map_err(AppExit::from)?;
Ok(())
} pub mod context;
pub mod help;
+pub mod stream;Update every FeatureAvailability block so streaming is marked as enabled:
feature_availability: FeatureAvailability {
- streaming: "optional add-on".to_string(),
+ streaming: "enabled".to_string(),
repl: "optional add-on".to_string(),
}Also add --stream to the global options rendered for the top-level and leaf
command paths so both plain-text and structured help stay accurate after the
feature is added.
Add the following paragraphs inside ## Output after the one-shot format description:
### Streaming Mode
- Activate streaming with `--stream`.
- `--stream --format yaml` writes YAML multi-document output using `---` before each record and `...` at the end.
- `--stream --format json` writes NDJSON, one compact JSON object per line.
- `--stream --format toml` is unsupported and must fail with a non-zero exit code and an explanation on stderr.- Expand
templates/repl.rs.tpltosrc/repl.rs. - Add the
--replflag and dispatch branch tosrc/main.rs. - Add
pub mod repl;tosrc/lib.rs. - Update
src/help.rsso the global option list includes--repland eachFeatureAvailabilityblock marks REPL as enabled. - Update
SKILL.mdwith aREPL Modesection betweenOutputandErrors. - Ensure the generated REPL behavior remains human-oriented:
- in-session REPL help is plain-text only
- command history is persisted under the CLI state root
- tab completion is enabled for command vocabulary and visible context values
- default REPL output favors readability, while any explicit structured result modes continue to honor the selected startup format
- Keep existing integration tests passing, and keep the unit tests bundled
inside
src/repl.rswhen the template provides them.
#[derive(Parser, Debug)]
#[command(
name = "<skill-name>",
version,
about = "<description>",
disable_help_flag = true,
disable_help_subcommand = true
)]
struct Cli {
...
+ /// Start an interactive read-eval-print loop
+ #[arg(long, global = true)]
+ repl: bool,
}Then, inside the main dispatch path, insert the REPL branch immediately after
let runtime_overrides = cli_runtime_overrides(&cli); and before the normal
command match:
let runtime_overrides = cli_runtime_overrides(&cli);
+ if cli.repl {
+ let runtime =
+ <crate_name>::context::resolve_runtime_locations(&runtime_overrides, false)?;
+ return <crate_name>::repl::start_repl(format, runtime);
+ }
match cli.command {
...
}Update every FeatureAvailability block so REPL is marked as enabled:
feature_availability: FeatureAvailability {
streaming: "optional add-on".to_string(),
- repl: "optional add-on".to_string(),
+ repl: "enabled".to_string(),
}Also add --repl to the global options rendered for the top-level and leaf
command paths so both plain-text and structured help stay accurate after the
feature is added.
+pub mod repl;
+
pub mod context;
pub mod help;Insert this section immediately after ## Output and before ## Errors:
## REPL Mode
- Start interactive mode with `--repl`.
- The prompt must be `<skill-name>> ` and must be written to stderr.
- `help` inside the REPL is plain text only and explains available commands,
context inspection controls, and output behavior.
- Each input line is handled as one command and the result is written to stdout.
Default session output may be more human-readable than one-shot YAML, but any
explicitly supported structured result mode must stay consistent with the
startup `--format`.
- Command history must persist under the runtime state directory.
- Tab completion must be available for command names, option names, and visible
context values.
- `exit`, `quit`, or EOF end the session with exit code `0`.
- Per-command errors are written to stderr and do not terminate the REPL.If the project already has one optional feature and you are adding the other:
- Keep both flags in the same
Clistruct. - Keep
--replas the early session-mode branch before the normal command match, and keep--streamscoped toexecute_run. - Keep exactly one
let output = ...;immediately before the default one-shot serialization path insideexecute_run. - Keep both module declarations in
src/lib.rs, and leave them in rustfmt-compatible order:
pub mod context;
pub mod help;
pub mod repl;
pub mod stream;-
Keep
src/help.rssynchronized with the enabled feature set by updating the global option list andFeatureAvailabilityvalues. -
Preserve the
SKILL.mdsection order:Description,Prerequisites,Invocation,Input,Output, optionalREPL Mode,Errors,Examples.
| Condition | Action |
|---|---|
feature is not stream or repl |
Reject the request and ask for a supported feature. |
project_path does not exist |
Stop and report the missing path. |
project_path is not a scaffolded Skill project |
Stop and explain which required file is missing. |
| Requested feature file already exists | Stop and tell the user no changes were made. |
| Template file is missing from this Skill package | Stop and report that the Skill package is incomplete. |
| Build/lint/format fails after applying the feature | Fix the project before reporting success. |
After a successful feature addition, tell the user:
- which feature was added
- which files were created or modified
- that build, test, clippy, and formatting checks pass