| """
|
| Top-level argparse construction for the hermes CLI.
|
|
|
| Lives in its own module so other modules (e.g. ``relaunch.py``) can
|
| introspect the parser to discover which flags exist without running the
|
| ``main`` fn.
|
|
|
| Only the top-level parser and the ``chat`` subparser live here. Every other
|
| subparser (model, gateway, sessions, …) is built inline in ``main.py``
|
| because its dispatch is tightly coupled to module-level ``cmd_*`` functions.
|
| """
|
|
|
| import argparse
|
|
|
|
|
|
|
|
|
|
|
|
|
| PRE_ARGPARSE_INHERITED_FLAGS: list[tuple[str, bool]] = [
|
| ("--profile", True),
|
| ("-p", True),
|
| ]
|
|
|
|
|
| def _inherited_flag(parser, *args, **kwargs):
|
| """Register a flag that ``hermes_cli.relaunch`` should carry over when
|
| the CLI re-execs itself (e.g. after ``sessions browse`` picks a session,
|
| or after the setup wizard launches chat).
|
|
|
| Equivalent to ``parser.add_argument(...)`` plus tagging the resulting
|
| Action with ``inherit_on_relaunch = True`` so the relaunch table builder
|
| can find it via introspection.
|
| """
|
| action = parser.add_argument(*args, **kwargs)
|
| action.inherit_on_relaunch = True
|
| return action
|
|
|
|
|
| _EPILOGUE = """
|
| Examples:
|
| hermes Start interactive chat
|
| hermes chat -q "Hello" Single query mode
|
| hermes -c Resume the most recent session
|
| hermes -c "my project" Resume a session by name (latest in lineage)
|
| hermes --resume <session_id> Resume a specific session by ID
|
| hermes setup Run setup wizard
|
| hermes logout Clear stored authentication
|
| hermes auth add <provider> Add a pooled credential
|
| hermes auth list List pooled credentials
|
| hermes auth remove <p> <t> Remove pooled credential by index, id, or label
|
| hermes auth reset <provider> Clear exhaustion status for a provider
|
| hermes model Select default model
|
| hermes fallback [list] Show fallback provider chain
|
| hermes fallback add Add a fallback provider (same picker as `hermes model`)
|
| hermes fallback remove Remove a fallback provider from the chain
|
| hermes config View configuration
|
| hermes config edit Edit config in $EDITOR
|
| hermes config set model gpt-4 Set a config value
|
| hermes gateway Run messaging gateway
|
| hermes -s hermes-agent-dev,github-auth
|
| hermes -w Start in isolated git worktree
|
| hermes gateway install Install gateway background service
|
| hermes sessions list List past sessions
|
| hermes sessions browse Interactive session picker
|
| hermes sessions rename ID T Rename/title a session
|
| hermes logs View agent.log (last 50 lines)
|
| hermes logs -f Follow agent.log in real time
|
| hermes logs errors View errors.log
|
| hermes logs --since 1h Lines from the last hour
|
| hermes debug share Upload debug report for support
|
| hermes update Update to latest version
|
| hermes dashboard Start web UI dashboard (port 9119)
|
| hermes dashboard --stop Stop running dashboard processes
|
| hermes dashboard --status List running dashboard processes
|
|
|
| For more help on a command:
|
| hermes <command> --help
|
| """
|
|
|
|
|
| def build_top_level_parser():
|
| """Build the top-level parser, the subparsers action, and the ``chat`` subparser.
|
|
|
| Returns ``(parser, subparsers, chat_parser)``. The caller wires
|
| ``chat_parser.set_defaults(func=cmd_chat)`` and continues registering
|
| other subparsers via ``subparsers.add_parser(...)``.
|
| """
|
| parser = argparse.ArgumentParser(
|
| prog="hermes",
|
| description="Hermes Agent - AI assistant with tool-calling capabilities",
|
| formatter_class=argparse.RawDescriptionHelpFormatter,
|
| epilog=_EPILOGUE,
|
| )
|
|
|
| parser.add_argument(
|
| "--version", "-V", action="store_true", help="Show version and exit"
|
| )
|
| parser.add_argument(
|
| "-z",
|
| "--oneshot",
|
| metavar="PROMPT",
|
| default=None,
|
| help=(
|
| "One-shot mode: send a single prompt and print ONLY the final "
|
| "response text to stdout. No banner, no spinner, no tool "
|
| "previews, no session_id line. Tools, memory, rules, and "
|
| "AGENTS.md in the CWD are loaded as normal; approvals are "
|
| "auto-bypassed. Intended for scripts / pipes."
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
| _inherited_flag(
|
| parser,
|
| "-m",
|
| "--model",
|
| default=None,
|
| help=(
|
| "Model override for this invocation (e.g. anthropic/claude-sonnet-4.6). "
|
| "Applies to -z/--oneshot and --tui. Also settable via HERMES_INFERENCE_MODEL env var."
|
| ),
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--provider",
|
| default=None,
|
| help=(
|
| "Provider override for this invocation (e.g. openrouter, anthropic). "
|
| "Applies to -z/--oneshot and --tui. The persistent provider lives in config.yaml "
|
| "under model.provider — use `hermes setup` or edit the file to change it."
|
| ),
|
| )
|
| parser.add_argument(
|
| "-t",
|
| "--toolsets",
|
| default=None,
|
| help="Comma-separated toolsets to enable for this invocation. Applies to -z/--oneshot and --tui.",
|
| )
|
| parser.add_argument(
|
| "--resume",
|
| "-r",
|
| metavar="SESSION",
|
| default=None,
|
| help="Resume a previous session by ID or title",
|
| )
|
| parser.add_argument(
|
| "--continue",
|
| "-c",
|
| dest="continue_last",
|
| nargs="?",
|
| const=True,
|
| default=None,
|
| metavar="SESSION_NAME",
|
| help="Resume a session by name, or the most recent if no name given",
|
| )
|
| parser.add_argument(
|
| "--worktree",
|
| "-w",
|
| action="store_true",
|
| default=False,
|
| help="Run in an isolated git worktree (for parallel agents)",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--accept-hooks",
|
| action="store_true",
|
| default=False,
|
| help=(
|
| "Auto-approve any unseen shell hooks declared in config.yaml "
|
| "without a TTY prompt. Equivalent to HERMES_ACCEPT_HOOKS=1 or "
|
| "hooks_auto_accept: true in config.yaml. Use on CI / headless "
|
| "runs that can't prompt."
|
| ),
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--skills",
|
| "-s",
|
| action="append",
|
| default=None,
|
| help="Preload one or more skills for the session (repeat flag or comma-separate)",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--yolo",
|
| action="store_true",
|
| default=False,
|
| help="Bypass all dangerous command approval prompts (use at your own risk)",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--pass-session-id",
|
| action="store_true",
|
| default=False,
|
| help="Include the session ID in the agent's system prompt",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--ignore-user-config",
|
| action="store_true",
|
| default=False,
|
| help="Ignore ~/.hermes/config.yaml and fall back to built-in defaults (credentials in .env are still loaded)",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--ignore-rules",
|
| action="store_true",
|
| default=False,
|
| help="Skip auto-injection of AGENTS.md, SOUL.md, .cursorrules, memory, and preloaded skills",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--tui",
|
| action="store_true",
|
| default=False,
|
| help="Launch the modern TUI instead of the classic REPL",
|
| )
|
| _inherited_flag(
|
| parser,
|
| "--dev",
|
| dest="tui_dev",
|
| action="store_true",
|
| default=False,
|
| help="With --tui: run TypeScript sources via tsx (skip dist build)",
|
| )
|
|
|
| subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
|
|
|
|
|
|
|
|
| chat_parser = subparsers.add_parser(
|
| "chat",
|
| help="Interactive chat with the agent",
|
| description="Start an interactive chat session with Hermes Agent",
|
| )
|
| chat_parser.add_argument(
|
| "-q", "--query", help="Single query (non-interactive mode)"
|
| )
|
| chat_parser.add_argument(
|
| "--image", help="Optional local image path to attach to a single query"
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "-m", "--model", help="Model to use (e.g., anthropic/claude-sonnet-4)",
|
| )
|
| chat_parser.add_argument(
|
| "-t", "--toolsets", help="Comma-separated toolsets to enable"
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "-s",
|
| "--skills",
|
| action="append",
|
| default=argparse.SUPPRESS,
|
| help="Preload one or more skills for the session (repeat flag or comma-separate)",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--provider",
|
|
|
|
|
|
|
|
|
| default=None,
|
| help="Inference provider (default: auto). Built-in or a user-defined name from `providers:` in config.yaml.",
|
| )
|
| chat_parser.add_argument(
|
| "-v",
|
| "--verbose",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help="Verbose output",
|
| )
|
| chat_parser.add_argument(
|
| "-Q",
|
| "--quiet",
|
| action="store_true",
|
| help="Quiet mode for programmatic use: suppress banner, spinner, and tool previews. Only output the final response and session info.",
|
| )
|
| chat_parser.add_argument(
|
| "--resume",
|
| "-r",
|
| metavar="SESSION_ID",
|
| default=argparse.SUPPRESS,
|
| help="Resume a previous session by ID (shown on exit)",
|
| )
|
| chat_parser.add_argument(
|
| "--continue",
|
| "-c",
|
| dest="continue_last",
|
| nargs="?",
|
| const=True,
|
| default=argparse.SUPPRESS,
|
| metavar="SESSION_NAME",
|
| help="Resume a session by name, or the most recent if no name given",
|
| )
|
| chat_parser.add_argument(
|
| "--worktree",
|
| "-w",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help="Run in an isolated git worktree (for parallel agents on the same repo)",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--accept-hooks",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help=(
|
| "Auto-approve any unseen shell hooks declared in config.yaml "
|
| "without a TTY prompt (see also HERMES_ACCEPT_HOOKS env var and "
|
| "hooks_auto_accept: in config.yaml)."
|
| ),
|
| )
|
| chat_parser.add_argument(
|
| "--checkpoints",
|
| action="store_true",
|
| default=False,
|
| help="Enable filesystem checkpoints before destructive file operations (use /rollback to restore)",
|
| )
|
| chat_parser.add_argument(
|
| "--max-turns",
|
| type=int,
|
| default=None,
|
| metavar="N",
|
| help="Maximum tool-calling iterations per conversation turn (default: 90, or agent.max_turns in config)",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--yolo",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help="Bypass all dangerous command approval prompts (use at your own risk)",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--pass-session-id",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help="Include the session ID in the agent's system prompt",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--ignore-user-config",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help="Ignore ~/.hermes/config.yaml and fall back to built-in defaults (credentials in .env are still loaded). Useful for isolated CI runs, reproduction, and third-party integrations.",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--ignore-rules",
|
| action="store_true",
|
| default=argparse.SUPPRESS,
|
| help="Skip auto-injection of AGENTS.md, SOUL.md, .cursorrules, memory, and preloaded skills. Combine with --ignore-user-config for a fully isolated run.",
|
| )
|
| chat_parser.add_argument(
|
| "--source",
|
| default=None,
|
| help="Session source tag for filtering (default: cli). Use 'tool' for third-party integrations that should not appear in user session lists.",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--tui",
|
| action="store_true",
|
| default=False,
|
| help="Launch the modern TUI instead of the classic REPL",
|
| )
|
| _inherited_flag(
|
| chat_parser,
|
| "--dev",
|
| dest="tui_dev",
|
| action="store_true",
|
| default=False,
|
| help="With --tui: run TypeScript sources via tsx (skip dist build)",
|
| )
|
|
|
| return parser, subparsers, chat_parser
|
|
|