diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-08-14 04:22:48 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-08-14 04:22:48 +0300 |
| commit | 1af1a5b86f642ae7b053037bc472913cfbc1e206 (patch) | |
| tree | 9b2826f592bcaa5420149d9e9752a79ec9ed9d30 | |
| parent | 1ac5e9805784e14a5322a0e60e435348149721ee (diff) | |
feat(cli): guide agents to Herdr resources
| -rw-r--r-- | .agents/skills/herdr-pre-release-audit/SKILL.md | 1 | ||||
| -rw-r--r-- | .agents/skills/herdr-pre-release-audit/references/pre-release-audit.md | 4 | ||||
| -rw-r--r-- | docs/next/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | justfile | 1 | ||||
| -rw-r--r-- | src/cli.rs | 9 | ||||
| -rw-r--r-- | src/cli/spec.rs | 30 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | tests/cli/surface.rs | 27 |
8 files changed, 71 insertions, 5 deletions
diff --git a/.agents/skills/herdr-pre-release-audit/SKILL.md b/.agents/skills/herdr-pre-release-audit/SKILL.md index 585bd177..ce5e7d01 100644 --- a/.agents/skills/herdr-pre-release-audit/SKILL.md +++ b/.agents/skills/herdr-pre-release-audit/SKILL.md @@ -13,6 +13,7 @@ Read `references/pre-release-audit.md` and follow its workflow. Treat it as the - inspecting first-parent history and merged PRs - auditing `docs/next/CHANGELOG.md` - auditing `docs/next/README.md` and staged website docs +- checking `skills/herdr/SKILL.md` against shipped CLI and agent-control behavior - checking issue reference lines - deciding when to run `just pre-release-check` or its component checks - running and assessing `just bench-render-scale` diff --git a/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md b/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md index c3e14c1b..2dfcb4d4 100644 --- a/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md +++ b/.agents/skills/herdr-pre-release-audit/references/pre-release-audit.md @@ -69,6 +69,7 @@ Process: - Compare English next-release website docs against `docs/next/website/src/content/docs/ja/` and `docs/next/website/src/content/docs/zh-cn/`. Flag missing localized files, stale localized files, and heading-outline drift where translated docs do not have the same section structure as English. - Compare `docs/next/README.md` and the next website draft against current stable docs. Flag each difference as intended to ship, stale, or needing user decision. Do not require the draft and stable trees to match before release. - Also audit example config snippets for release readiness. + - Audit `skills/herdr/SKILL.md` against shipped changes to the CLI, public IDs, pane and agent workflows, lifecycle semantics, and safety guidance. Flag stale commands, options, examples, or behavioral claims. The binary bundles this exact file, so review semantic freshness rather than file synchronization. 8. Verify finalization state. - Before `just release`, approved README changes must be finalized in `docs/next/README.md`; release CI promotes that tagged file after publication. Do not copy draft website docs into `website/src/content/docs/` or `docs/preview/`. @@ -116,6 +117,9 @@ Accepted/no action: Root docs finalized: YES | NO <result of just release-docs-check or why it was not run> +Agent skill: UP TO DATE | NEEDS UPDATE | NOT CHECKED +<whether skills/herdr/SKILL.md matches the shipped CLI and agent-control behavior> + Nix Cargo lock integration: OK | NEEDS ATTENTION | NOT CHECKED <result of nix flake check or any required cargoLock.outputHashes status> diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md index 99940c40..797813ef 100644 --- a/docs/next/CHANGELOG.md +++ b/docs/next/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased ### Added +- CLI help now points coding agents to Herdr's plain-text guide, documentation index, and built-in control skill. - Added Qwen Code detection for idle, working, and user-confirmation states, plus optional native session restore. - Herdr now keeps the outer terminal window title in sync with the session through `ui.window_title`, so window managers and terminal tab bars show the active workspace and the host the panes actually run on. - The desktop tab bar now has configurable right-aligned status entries for zoom state, hostname, date/time, literal text, and asynchronously refreshed command output. @@ -135,6 +135,7 @@ pre-release-check: just release-docs-check just bench-render-scale @echo "release review required: investigate material render-scaling regressions before publishing." + @echo "release review required: verify skills/herdr/SKILL.md matches the current CLI, IDs, agent lifecycle semantics, and safety guidance." # Prepare the release commit without tagging or pushing (usage: just release-prepare 0.1.1) release-prepare version: @@ -29,6 +29,15 @@ const TERMINAL_SESSION_OBSERVE_USAGE: &str = "usage: herdr terminal session observe <target> [--cols N] [--rows N]"; const TERMINAL_SESSION_CONTROL_USAGE: &str = "usage: herdr terminal session control <target> [--takeover] [--cols N] [--rows N]"; +pub(crate) const AGENT_HELP_FOOTER: &str = concat!( + "Are you an AI? Use these resources ONLY IF your task specifically asks you to:\n", + " Help a human understand or set up Herdr for the first time:\n", + " https://herdr.dev/agent-guide.md\n", + " Debug or investigate a problem with Herdr:\n", + " https://herdr.dev/llms.txt\n", + " Control Herdr panes, agents, or workspaces:\n", + " SKIP if a Herdr skill is already in your context. Otherwise run: herdr --skill", +); pub(crate) fn parse_token_assignment(raw: &str) -> Result<(String, Option<String>), String> { let Some((key, value)) = raw.split_once('=') else { diff --git a/src/cli/spec.rs b/src/cli/spec.rs index ba454bfc..b2b6cb03 100644 --- a/src/cli/spec.rs +++ b/src/cli/spec.rs @@ -43,18 +43,23 @@ pub(super) fn command() -> Command { .subcommand(session_command()) .subcommand(integration_command()) .subcommand(plugin_command()); - configure_help(command, true) + configure_help(command, 0) } -fn configure_help(command: Command, root: bool) -> Command { - let command = if root { +fn configure_help(command: Command, depth: usize) -> Command { + let command = if depth == 0 { command } else { command.disable_help_flag(false) }; + let command = if depth == 1 && command.has_subcommands() { + command.after_help(super::AGENT_HELP_FOOTER) + } else { + command + }; command .disable_help_subcommand(true) - .mut_subcommands(|subcommand| configure_help(subcommand, false)) + .mut_subcommands(|subcommand| configure_help(subcommand, depth + 1)) } pub(super) fn print_requested_help(args: &[String]) -> std::io::Result<bool> { @@ -1307,6 +1312,23 @@ mod tests { } #[test] + fn agent_resources_appear_on_command_groups_but_not_leaf_commands() { + for group in ["agent", "pane", "workspace", "terminal"] { + let help = long_help(&[group]); + assert!( + help.contains(super::super::AGENT_HELP_FOOTER), + "herdr {group} is missing agent resources: {help}" + ); + } + + let leaf = long_help(&["agent", "wait"]); + assert!( + !leaf.contains(super::super::AGENT_HELP_FOOTER), + "leaf help should stay focused: {leaf}" + ); + } + + #[test] fn next_step_hints_render_without_replacing_existing_after_help() { let agent_start = long_help(&["agent", "start"]); assert!( diff --git a/src/main.rs b/src/main.rs index d3b72192..868c0b5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -715,7 +715,8 @@ fn main() -> io::Result<()> { println!("Logs: {}", logging::help_log_paths_summary()); println!("Env: HERDR_CONFIG_PATH overrides config file path"); println!("Home: https://herdr.dev"); - println!("Skill: herdr --skill prints agent instructions for driving herdr from a pane"); + println!(); + println!("{}", cli::AGENT_HELP_FOOTER); return Ok(()); } diff --git a/tests/cli/surface.rs b/tests/cli/surface.rs index 2507804e..b48baf57 100644 --- a/tests/cli/surface.rs +++ b/tests/cli/surface.rs @@ -274,6 +274,33 @@ fn help_commands_exit_successfully() { } #[test] +fn root_and_command_group_help_point_agents_to_plain_text_docs() { + for args in [&["--help"][..], &["agent", "--help"][..]] { + let output = Command::new(env!("CARGO_BIN_EXE_herdr")) + .args(args) + .env_remove("HERDR_SOCKET_PATH") + .env_remove("HERDR_CLIENT_SOCKET_PATH") + .env_remove("HERDR_ENV") + .output() + .unwrap(); + assert!(output.status.success(), "herdr {} failed", args.join(" ")); + let stdout = String::from_utf8_lossy(&output.stdout); + for expected in [ + "Are you an AI? Use these resources ONLY IF your task specifically asks you to:", + "https://herdr.dev/agent-guide.md", + "https://herdr.dev/llms.txt", + "herdr --skill", + ] { + assert!( + stdout.contains(expected), + "herdr {} help did not contain {expected:?}: {stdout}", + args.join(" ") + ); + } + } +} + +#[test] fn subcommand_help_explains_automation_semantics_without_a_server() { let cases: &[(&[&str], &str)] = &[ (&["agent", "wait", "--help"], "Without --until"), |
