一键导入
add-cli-flag
Step-by-step checklist for adding a new CLI flag to openshell-image-builder, covering all locations from the clap struct to integration tests
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Step-by-step checklist for adding a new CLI flag to openshell-image-builder, covering all locations from the clap struct to integration tests
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Understand and edit the OpenShell sandbox policy — base YAML, network rule schema, how inference and agent fragments are merged, and how to test changes
Step-by-step checklist for adding a new inference provider to openshell-image-builder, covering the trait implementation, agent wiring, unit tests, integration tests, and README
Step-by-step checklist for adding a new agent to openshell-image-builder, covering the Agent trait, mod.rs registration, unit tests, integration tests, and README
Step-by-step checklist for adding a new base image to openshell-image-builder, covering the Containerfile match arm, unit tests, and integration tests
Create a new project skill in .agents/skills/ and register it in the skills README
Run the pre-commit check suite — cargo fmt, clippy, and unit tests — and fix formatting automatically if needed
| name | add-cli-flag |
| description | Step-by-step checklist for adding a new CLI flag to openshell-image-builder, covering all locations from the clap struct to integration tests |
| argument-hint | <flag-name> <description> |
End-to-end checklist for introducing a new CLI argument to openshell-image-builder.
Every CLI flag touches at least four files. Missing any one of them compiles fine but leaves the flag silently unused or untested. Follow the steps below in order.
The existing flags are the canonical reference:
--agent / --inference — enum flags backed by ValueEnum, gated by a compatibility check in run()--endpoint — Option<String> that overrides a provider URL, validated early in run(), flows into resolve_base_url() and stage_agent_settings()--model — Option<String> threaded through stage_agent_settings() and agent.env_vars()--ssl-certs — Option<String> with num_args = 0..=1 and default_missing_value = "" (optional value flag); converted to Option<Option<PathBuf>> before being passed to run()Cli struct (src/main.rs)Add a field to the Cli struct with a #[arg(...)] attribute:
#[arg(long, help = "Short description shown in --help")]
my_flag: Option<String>, // or bool, Option<MyEnum>, etc.
Common patterns:
Option<String> — optional string value (--my-flag value)Option<MyEnum> where MyEnum: ValueEnum — enum with validated variantsbool with action = clap::ArgAction::SetTrue — a plain switchrun() (src/main.rs)In main(), add the field to the run() call:
cli.my_flag.as_deref(), // for Option<String>
cli.my_flag, // for bool or Option<Enum>
Then extend the run() signature:
fn run(
...
my_flag: Option<&str>, // add here
ssl_certs: Option<Option<PathBuf>>,
runner: &dyn build::Runner,
) -> Result<(), Box<dyn std::error::Error>> {
run() already has #[allow(clippy::too_many_arguments)] — no need to add it again.
run() (src/main.rs)If the new flag has incompatible combinations with existing flags, reject them at the top of run() before any work begins, following the --endpoint + vertexai pattern:
if my_flag.is_some() && some_condition {
return Err("--my-flag is not supported when ...".into());
}
Keep error messages lowercase, starting with the flag name.
Where the flag's effect lives depends on what it does:
Thread it through stage_agent_settings() (for agent config files / env vars) or add a new staging function following the stage_skills() pattern.
Pass it to build_policy() and into the relevant inference.policy_yaml() or agent.policy_yaml() implementation.
Pass it to containerfile::generate() in src/containerfile.rs.
AgentKind or InferenceKind (both derive ValueEnum, so clap picks it up automatically).src/agent/ or src/inference/.mod declaration and the from_kind arm in src/agent/mod.rs or src/inference/mod.rs.#[cfg(test)] for unit test use — follow the existing pattern:
#[cfg(test)]
pub use my_module::MyImpl;
src/main.rs, #[cfg(test)])Add tests that exercise the new parameter through run() using FakeRunner, which fakes the podman call:
#[test]
fn run_with_my_flag_succeeds() {
let tmp = tempfile::tempdir().unwrap();
let result = run(
"test:latest",
Some(tmp.path().to_path_buf()),
tmp.path(),
None, // agent_kind
None, // inference_kind
None, // endpoint
None, // model
Some("my-value"), // my_flag
None, // ssl_certs
&FakeRunner(0),
);
assert!(result.is_ok(), "expected Ok, got {result:?}");
}
If the flag has rejection logic, add a dedicated test that asserts result.is_err() and checks the error message text.
For flags that write files into the image context, test through stage_agent_settings() or the relevant staging function directly — those functions take a context_dir and you can assert on the files created there.
tests/integration_test.rs)static MY_IMAGE: OnceLock<String> = OnceLock::new(); alongside the related statics.fn my_image() -> &'static str { MY_IMAGE.get_or_init(|| build_image("openshell-test-my-variant:integration", &["--my-flag", "value"])) }.cleanup_images array in the #[ctor::dtor] at the bottom of the file.Add a mod my_flag { use super::*; ... } block with at least:
stat -c '%U' returns "sandbox").#[ignore] because they never call podman.README.mdThe README has five places that may need updating. The first is mandatory; the rest depend on the flag's scope.
At the bottom of the README, every flag appears in this table. Add a row:
| `--my-flag <VALUE>` | Short description matching the clap `help` string |
The numbered list near the top of the README describes what the tool assembles layer by layer. If the new flag introduces a genuinely new layer (or a new bullet under an existing layer), update that list. For a sub-capability of an existing layer, add an indented bullet following the --endpoint and --model style.
This table has a row per agent and a column per capability. Add a column if the flag exposes a capability that only some agents support:
| Agent | ... | My Feature |
| ---------- | --- | ---------- |
| `claude` | ... | Yes / No |
| `opencode` | ... | Yes / No |
Add a column to the existing table, following the "Endpoint override" or "Model selection" pattern — include the mechanism (what file or env var is written) in the cell, not just Yes/No.
Flags with their own behavior description get either:
## section (if the flag is the primary subject, like --agent or --inference).### subsection inside an existing section (like --endpoint and --model live under "Configuring inference").The section should cover: what the flag does, any per-agent or per-agent×inference variations (link to the table if one exists), and a sh code block with at least one concrete example command.
Cli struct with #[arg(...)]main() → run() signature → run() bodyrun() with a clear error#[cfg(test)] if applicablemod block covers positive, ownership, negative, and rejection cases/check passes (fmt + clippy + unit tests)/copyright-headers run on any new .rs files