amplihack-rs Parity Reference¶
This reference describes Rust subprocess prompt delivery parity for amplihack
launcher, orchestration, auto-mode, and doctor surfaces.
Subprocess prompt delivery¶
amplihack-rs routes prompt-bearing subprocess launches through
amplihack-utils::prompt_delivery. The delivery engine supports three concrete
prompt channels:
| Mode | Behavior | Primary use |
|---|---|---|
argv |
Appends the prompt as one structured process argument. | Short prompts and binaries with no long-form prompt channel. |
tempfile |
Writes the prompt to a restricted temporary file and passes the file path using the binary's verified prompt-file contract. | Long prompts when the target binary supports prompt files. |
stdin |
Pipes the prompt to child stdin, then closes stdin before waiting for the child. | Long prompts when the target binary supports prompt input from stdin. |
The Rust launcher, orchestration, and auto-mode paths use the same selector and capability metadata. A long prompt is not manually shell-escaped or interpolated into a shell command string.
Parity status¶
| Parity area | Rust behavior |
|---|---|
| Subprocess prompt delivery | argv, tempfile, and stdin are selected through amplihack-utils::prompt_delivery using static per-binary capabilities. Unsupported explicit tempfile requests degrade to stdin when supported, otherwise argv, unless a binary-specific contract requires rejection. Unsupported explicit stdin requests degrade directly to argv, unless a binary-specific contract requires rejection. |
Configuration¶
Set AMPLIHACK_PROMPT_DELIVERY to choose the requested prompt delivery mode.
This setting applies to migrated subprocess launch paths.
# Default: choose the safest supported channel for the target binary and prompt size.
unset AMPLIHACK_PROMPT_DELIVERY
amplihack claude -- "Summarize this repository"
# Request prompt-file delivery when the selected binary supports it.
AMPLIHACK_PROMPT_DELIVERY=tempfile \
amplihack claude -- "Review this 64 KiB prompt without shell parsing"
# Request stdin delivery once the selected binary has a verified stdin contract.
AMPLIHACK_PROMPT_DELIVERY=stdin \
amplihack codex -- "Analyze this generated task description"
# Force argv delivery for compatibility diagnostics.
AMPLIHACK_PROMPT_DELIVERY=argv \
amplihack copilot -- "Short prompt"
AMPLIHACK_PROMPT_DELIVERY¶
| Value | Meaning |
|---|---|
unset, empty, or auto |
Use automatic mode selection. |
argv |
Request structured argv delivery. |
tempfile |
Request temporary-file delivery. |
stdin |
Request stdin delivery. |
Values are case-insensitive. Unknown values resolve to auto and emit a
warning. The environment variable is a request, not a capability override: a
binary only uses tempfile or stdin when the launcher has a verified contract
for that binary.
Amplifier is the explicit rejection case: AMPLIHACK_PROMPT_DELIVERY=tempfile
and AMPLIHACK_PROMPT_DELIVERY=stdin must fail before launching Amplifier
because Amplifier has no documented task-prompt file or stdin contract.
Binary capability matrix¶
Capabilities are static launcher metadata, not user-controlled configuration. Tempfile and stdin support are only marked when the binary has a verified task-prompt contract for that channel.
| Binary | argv |
tempfile |
Tempfile flag | stdin |
Notes |
|---|---|---|---|---|---|
| Claude Code | Supported | Pending verification | None for task prompts | Unsupported | --append-system-prompt is a system-prompt file contract. It must not be used for task-prompt delivery unless the implementation intentionally changes prompt role and documents that role change. Until a verified task-prompt file contract exists, Claude task prompts remain on argv. |
| GitHub Copilot CLI | Supported | Unsupported | None | Unsupported | Copilot receives prompts through argv because no verified prompt-file or stdin prompt contract is advertised. |
| Codex | Supported | Unsupported | None | Pending verification | Codex stdin delivery requires a named, tested command contract that reads the task prompt from stdin. Until that contract is verified, Codex task prompts remain on argv. |
| Microsoft Amplifier | Supported | Unsupported | None | Unsupported | Amplifier is routed through prompt_delivery, but tempfile and stdin remain unsupported because Amplifier documents run [PROMPT] and does not document a task-prompt file or stdin contract. |
When a future binary version adds a prompt-file or stdin contract, update
crates/amplihack-launcher/src/flag_matrix.rs first, then update this table.
Amplifier prompt-delivery contract¶
Amplifier task prompts are argv-only because the documented upstream prompt shape is:
| Capability | Amplifier behavior |
|---|---|
| Structured argv prompt | Supported. The task prompt is one Command::arg value. |
| Temporary prompt file | Unsupported. Amplifier does not document a --prompt-file, --prompt-path, or equivalent task-prompt file option. |
| Stdin task prompt | Unsupported. Amplifier does not document stdin as a task-prompt input channel. |
AMPLIHACK_PROMPT_DELIVERY=tempfile and
AMPLIHACK_PROMPT_DELIVERY=stdin fail before spawning Amplifier. The launcher
does not create a temporary prompt file, write prompt bytes to stdin, silently
degrade to argv, add a synthetic --prompt flag, or interpolate prompts into
shell command strings.
Evidence required to enable Amplifier long-form delivery¶
Do not enable Amplifier tempfile or stdin support from observed behavior,
internal experiments, or generic prompt_delivery support alone. The launcher
capability matrix can mark Amplifier as supporting a long-form channel only when
upstream Amplifier exposes a documented, stable task-prompt contract such as:
- a named prompt-file option in
amplifier run --help, - documentation that stdin is read as the task prompt for a named command mode,
- or an upstream release note/API document that commits to one of those contracts.
When that evidence exists, update flag_matrix.rs, add round-trip regression
coverage for a 64 KiB prompt containing apostrophes, and update this reference.
Mode selection¶
prompt_delivery resolves a requested mode into an effective mode using the
prompt size and the selected binary's capabilities.
| Requested mode | Selection rule |
|---|---|
auto |
Use argv for prompts at or below 4096 bytes when supported. For larger prompts, prefer tempfile, then stdin, then argv. |
argv |
Use argv when supported; otherwise degrade to tempfile, then stdin, then argv. |
tempfile |
Use tempfile when supported; otherwise degrade to stdin, then argv. |
stdin |
Use stdin when supported; otherwise degrade directly to argv. Do not degrade an explicit stdin request to tempfile, because stdin and prompt-file delivery have different process contracts. |
Every unsupported explicit-mode degradation emits a warning that names the requested mode and the effective mode. The warning does not include the raw prompt, temporary-file contents, or stdin payload.
Binary-specific rejection rules override the generic degradation table. For
Amplifier, explicit tempfile and stdin requests are invalid and must fail
before execution.
Usage examples¶
Send a long prompt safely through auto mode¶
Create a long prompt and let amplihack choose the safest supported delivery channel for the child binary.
python3 - <<'PY' > /tmp/amplihack-long-prompt.txt
print("Review this text safely: " + ("don't shell-expand $HOME; " * 4096))
PY
AMPLIHACK_PROMPT_DELIVERY=auto \
amplihack claude -- "$(cat /tmp/amplihack-long-prompt.txt)"
This shell form still passes the prompt to the parent amplihack process as one
argv element. The parity guarantee in this document applies to the child agent
subprocess launched by amplihack. Until Claude has a verified task-prompt
tempfile contract, the effective child delivery mode for Claude is argv.
Diagnose unsupported requested modes¶
Requesting tempfile delivery for a generic binary without a verified tempfile contract degrades safely unless the binary has a stricter rejection rule.
For Amplifier, doctor reports capabilities: argv. Runtime Amplifier launches
reject explicit tempfile and stdin requests before launch and pass prompts
as structured argv only when the requested mode is unset, auto, or argv.
Run Amplifier with the documented prompt channel¶
Amplifier's documented prompt input is the positional PROMPT argument on
amplifier run.
This remains argv delivery even when the prompt is long. If the prompt must stay out of child argv, use a different agent binary with a verified long-form prompt contract; Amplifier has no supported tempfile or stdin task-prompt channel.
Use prompt delivery in auto-mode¶
Auto-mode prompt-bearing wrappers use prompt delivery. Ordinary Amplifier passthrough launch validates the same Amplifier unsupported-mode policy before spawning the child process.
AMPLIHACK_PROMPT_DELIVERY=auto \
amplihack auto --agent claude --task "$(cat /tmp/amplihack-long-prompt.txt)"
The DeliveryHandle returned by the prompt delivery engine is owned until the
subprocess exits. For future verified tempfile contracts, that keeps the
temporary prompt file available for the entire child lifetime.
Rust API¶
The generic delivery engine lives in amplihack-utils. The low-level API exists
for delivery mutation; launcher-level command building wraps it with binary
capability metadata.
use std::process::Command;
use amplihack_utils::prompt_delivery::{
DeliveryCaps, DeliveryHandle, DeliveryMode, PromptDelivery, deliver, from_env,
};
fn build_command(prompt: &str) -> std::io::Result<(Command, DeliveryHandle)> {
let mut cmd = Command::new("claude");
let requested = from_env();
let caps = DeliveryCaps::argv_only();
let handle = deliver(&mut cmd, prompt, requested, &caps)?;
Ok((cmd, handle))
}
Public types include PromptDelivery, DeliveryMode, DeliveryCaps, and
DeliveryHandle. Public functions include from_env(),
select_mode(requested, prompt_size, caps), and
deliver(cmd, prompt, requested, caps).
Launcher API¶
Launcher command builders expose delivery-aware construction instead of pushing prompt strings directly into argv.
use amplihack_launcher::flag_matrix::AgentBinary;
use amplihack_launcher::prompt_delivery::build_tool_command_with_prompt_delivery;
use amplihack_utils::prompt_delivery::PromptDelivery;
let delivered = build_tool_command_with_prompt_delivery(
AgentBinary::Claude,
std::env::current_dir()?.as_path(),
&[],
"Summarize this repository",
PromptDelivery::Auto,
)?;
let mut child = delivered.command.spawn()?;
let status = child.wait()?;
drop(delivered.delivery_handle);
The DeliveredCommand shape is:
| Field | Meaning |
|---|---|
command |
Structured std::process::Command with prompt delivery applied. |
delivery_handle |
RAII handle that owns tempfile resources or marks stdin ownership. |
requested_mode |
Mode requested by configuration. |
selected_mode |
Mode actually selected for the target binary. |
warnings |
Deterministic degradation or invalid-configuration warnings safe for logs. |
stdin_payload |
Prompt bytes to write when the effective mode is stdin; absent for argv and tempfile. |
Async orchestration contract¶
Async orchestration builds a std::process::Command, applies
prompt_delivery::deliver, then convert the command to tokio::process::Command
for spawning. It does not duplicate delivery selection logic.
When the effective mode is stdin, orchestration writes the complete prompt to
child stdin, flushes it, drops stdin to close the pipe, then awaits child exit.
The DeliveryHandle remains owned until after wait completes.
Doctor reporting¶
amplihack doctor reports prompt delivery diagnostics without printing prompt
contents.
Example output:
Prompt delivery
requested: tempfile
auto threshold: 4096 bytes
claude
capabilities: argv
note: task-prompt tempfile support pending verified Claude contract
effective for long prompt: argv
copilot
capabilities: argv
effective for long prompt: argv
warning: requested tempfile is unsupported; degrading to argv
codex
capabilities: argv
note: stdin support pending verified Codex command contract
effective for long prompt: argv
warning: requested tempfile is unsupported; degrading to argv
amplifier
capabilities: argv
effective for long prompt: argv
warning: requested tempfile is unsupported; degrading to argv
Doctor diagnostics are deterministic:
- they list the requested mode,
- they list static capabilities per binary,
- they show the effective mode for a long prompt,
- they show degradation warnings when a requested mode is unsupported,
- they never include raw prompt data.
Doctor is a capability report. It shows the effective delivery mode for each
binary under the requested setting, but it does not model every launch-time
policy. The Amplifier launch path is stricter than the generic doctor
degradation report: explicit tempfile and stdin launch requests fail before
spawning amplifier instead of degrading to argv.
Regression contract¶
Prompt delivery behavior is defined by these externally visible contracts:
| Contract | Required behavior |
|---|---|
| Long prompt privacy | For every migrated command builder with a verified long-form mode, a raw 64 KiB prompt containing apostrophes is absent from child argv when auto, tempfile, or stdin selects that long-form delivery mode. Binaries with only argv support are explicitly exempt and must still pass the prompt as one structured argv element. |
| Prompt fidelity | The same 64 KiB apostrophe-containing prompt round-trips unchanged through the selected delivery channel. |
| Structured argv safety | When argv is selected, the prompt is passed as one argv element. Apostrophes, quotes, semicolons, dollar signs, and shell metacharacters are not interpreted by a shell. |
| Unsupported tempfile request | A requested tempfile mode degrades to stdin when supported, otherwise to argv, and emits a warning, unless the target binary has a stricter rejection policy. |
| Unsupported stdin request | A requested stdin mode degrades directly to argv and emits a warning, unless the target binary has a stricter rejection policy. It does not degrade to tempfile. |
| Amplifier unsupported mode request | For Amplifier, explicit tempfile and stdin requests fail before spawning amplifier; they do not degrade to argv. |
| Tempfile lifetime | Tempfile prompts remain readable until the child process exits and are unlinked when the DeliveryHandle is dropped. |
| Stdin lifecycle | Stdin payloads are written completely, flushed, and closed before the child is awaited. |
| Diagnostics safety | Doctor output, logs, and warnings include modes, capabilities, and degradation messages, but never include raw prompt bytes. |
Security and lifecycle guarantees¶
Prompt delivery follows these guarantees:
| Guarantee | Detail |
|---|---|
| No shell command construction | Prompts are passed through Command argv, restricted tempfiles, or child stdin. |
| No prompt logging | Diagnostics and warnings describe modes and capabilities only. |
| Restricted tempfiles | Tempfile prompts are created with owner-only permissions on Unix and are unlinked by RAII drop. |
| Child-lifetime ownership | DeliveryHandle lives until the child exits, preventing premature tempfile deletion. |
| Closed stdin | Stdin payloads are written, flushed, and closed before waiting, preventing deadlocks. |
| Static capabilities | Users cannot force an unsupported binary to claim tempfile or stdin support. |
| Deterministic handling | Unsupported modes either degrade through the documented order with warnings or fail through a documented binary-specific rejection policy. |
Troubleshooting¶
A requested mode is not used or is rejected¶
Run doctor with the same environment:
If the selected binary lists only argv, the requested long-form mode is not
available for that binary. Doctor reports capability selection only; the
Amplifier launch path separately rejects explicit tempfile and stdin
requests before launch. Use a binary with a verified long-form prompt contract
or leave AMPLIHACK_PROMPT_DELIVERY=auto.
A long prompt still appears in argv¶
Check the binary capability row in doctor output. Long prompts remain in child
argv when the target binary has no verified tempfile or stdin task-prompt
contract.
A tempfile prompt disappears before the child reads it¶
Keep the returned DeliveryHandle alive until after the child process has been
waited on. Dropping the handle unlinks the tempfile.
A stdin-launched child hangs¶
Write the full stdin payload, flush it, then drop the stdin handle before awaiting process exit. Holding stdin open can make the child wait for more input.