Enhance CLI: Adding `erk Create` & Docs

by Alex Johnson 40 views

Introduction

This document details the plan to enhance the command-line interface (CLI) of our application by adding a new command, erk create, and providing comprehensive documentation for the CLI organization. This enhancement aims to streamline the process of creating GitHub issues with the erk-plan label and improve the overall user experience. The primary goal is to make the CLI more intuitive and efficient for users, especially those involved in orchestration and Unix composability.

Part 1: erk create Command

Interface Design

The erk create command will offer several modes of operation to cater to different user preferences and use cases. The primary mode, designed for orchestration, involves reading from a file. Users can specify the plan file using the --file option, and the command will automatically extract the title from the file's first H1 heading. For example:

erk create --file plan.md

To override the automatically extracted title, users can use the --title option:

erk create --file plan.md --title "Custom Title"

For Unix composability, the command will also support reading from stdin. This allows users to pipe content to the erk create command, enabling seamless integration with other command-line tools. For instance:

cat plan.md | erk create

Similar to the file mode, users can override the title when reading from stdin:

cat plan.md | erk create --title "Custom Title"

Additionally, the command will support adding multiple labels to the created issue using the --label option. This allows users to categorize and prioritize issues effectively:

erk create --file plan.md --label bug --label urgent

Input Modes (Priority Order)

The erk create command will support two primary input modes, with a clear priority order to avoid ambiguity. The first and most preferred mode is reading from a file specified via the --file PATH option. This mode is ideal for orchestration and automated workflows. The second mode involves reading from stdin, enabling Unix composability and integration with other tools. In cases where both --file and stdin are provided, the command will exit with an error message to prevent confusion. Furthermore, if stdin is a TTY (i.e., no data is being piped in) and no --file is provided, the command will also exit with an error message, prompting the user to provide input via --file or stdin. The command will not attempt to read from interactive input to avoid unexpected behavior in automated scripts. The --body option will not be included to keep the command structure simple.

Title Resolution

The erk create command offers flexible title resolution to accommodate various input formats. The title for the created issue can be determined in one of three ways, with a clear priority order. The highest priority is given to the explicit --title flag. If this flag is provided, the specified title will be used. If the --title flag is not provided, the command will attempt to extract the title from the content. It will first look for the first H1 heading (# Title), then the first H2 heading (## Title), and finally, the first non-empty line in the content. If no title can be found through these methods and no --title flag is provided, the command will exit with an error message.

Output

Upon successful creation of the issue, the erk create command will provide clear and informative output to the user. The output will include the issue number, a URL to the created issue on GitHub, and a set of next steps to guide the user through the subsequent workflow. The output will follow this format:

Created plan #42

Issue: https://github.com/owner/repo/issues/42

Next steps:
 View: erk get 42
 Implement: erk implement 42
 Submit: erk submit 42

Files to Create/Modify

To implement the erk create command, several files will need to be created or modified. A new file, src/erk/cli/commands/plan/create_cmd.py, will be created to house the main command implementation. The src/erk/cli/cli.py file will be modified to register the create_plan command as erk create, placing it appropriately among the existing plan commands. Additionally, a new test file, tests/commands/plan/test_create.py, will be created to provide comprehensive test coverage for the new command.

Implementation Details

The implementation of the erk create command will follow a structured approach, mirroring the pattern used in close_cmd.py. The command will be implemented as a plain function decorated with @click.command("create") to register it as a CLI command. It will accept options such as --file, --title, and --label using @click.option(). The command will also use @click.pass_obj to receive the ErkContext, providing access to necessary resources like the issue tracker and configuration. The core flow involves reading content from either the --file or stdin, extracting and validating the title, ensuring the erk-plan label exists, creating the issue with the Schema V2 format (metadata in the body and plan content in the first comment), and displaying a success message with the issue URL and next steps. Stdin handling will use sys.stdin.isatty() to detect piped input, and an error message will be displayed if no input is provided. For testing purposes, a stdin_reader will be added to ErkContext to allow faking stdin in tests.

Test Cases

A comprehensive suite of test cases will be implemented to ensure the reliability and correctness of the erk create command. These test cases will cover various scenarios, including creating an issue from a file (test_create_from_file()), creating an issue from stdin (test_create_from_stdin()), automatically extracting the title from an H1 heading (test_create_extracts_h1_title()), overriding the title with an explicit title (test_create_with_explicit_title()), adding additional labels (test_create_with_additional_labels()), handling errors when no input is provided (test_create_fails_with_no_input()), detecting conflicts between file and stdin input (test_create_fails_with_file_and_stdin()), ensuring the erk-plan label exists (test_create_ensures_label_exists()), and verifying the use of Schema V2 format (test_create_uses_schema_v2()).

Part 2: CLI Organization Documentation

Document Location

The CLI organization documentation will be located at docs/agent/cli-command-organization.md. This location was selected to group the CLI documentation together.

Document Outline

The documentation will provide a clear and structured overview of the CLI command organization, adhering to the "plan is dominant noun" principle. The document will begin with an introduction to the design philosophy, emphasizing the importance of plan-oriented interfaces. It will then categorize the commands into top-level plan operations (e.g., ls, list, get, close, create, implement, submit, retry, log), grouped commands (e.g., erk wt for worktree operations, erk stack for stack operations), and navigation commands (e.g., checkout, up, down). A decision framework will be provided to guide the placement of new commands, along with implementation references and links to related documentation.

Cross-Reference Updates

To ensure the discoverability of the new CLI organization documentation, cross-references will be added in relevant locations. Specifically, the AGENTS.md file will be updated after line 71 (after the "Worktree Terminology" section) with a link to the new documentation, highlighting the "plan is dominant noun" principle and the grouping of worktree verbs. Additionally, the docs/agent/guide.md file will be updated to include a link to the CLI organization documentation in the Task-Based Navigation table.

Key Content Points

The CLI organization documentation will emphasize several key content points. It will clearly articulate the "plan is dominant noun" principle, explaining why plan operations are top-level commands for improved ergonomics. It will also describe how worktree and stack operations are grouped under erk wt and erk stack, respectively, to address infrastructure concerns. Furthermore, the documentation will provide a decision tree to assist developers in determining whether to place a new command at the top level or within a grouped command. Finally, it will include examples of good patterns and anti-patterns to illustrate the principles and best practices of CLI organization.

Implementation Order

The implementation will follow a specific order to ensure a smooth and efficient process. First, the erk create command (Part 1) will be created. Next, tests for the erk create command will be added to ensure its functionality and reliability. Then, the CLI organization documentation (Part 2) will be created to provide a comprehensive overview of the CLI structure. Finally, cross-references will be updated in AGENTS.md and guide.md to improve the discoverability of the new documentation.

Success Criteria

The success of this enhancement will be measured against several criteria. The erk create --file plan.md command must successfully create an issue with the erk-plan label. The title should be automatically extracted from the H1 heading when the --title option is not provided. The issue should be created using the Schema V2 format, with metadata in the body and the plan content in the first comment. The documentation should clearly explain the "plan is dominant noun" principle. Finally, the AGENTS.md file should reference the new documentation.

Context & Understanding

API/Tool Quirks

Several API and tool quirks need to be considered during implementation. Creating an issue and immediately adding a comment are two separate API calls in the GitHub API. The implementation must handle the case where issue creation succeeds but comment creation fails, resulting in an orphaned issue. The Schema V2 format requires the issue body to contain only the plan-header metadata block (created_at, created_by, worktree_name), while the actual plan content goes in the first comment wrapped in the plan-body metadata block. The ensure_label_exists() function must be called before issue creation to avoid label-not-found errors. Finally, stdin.isatty() returns True when stdin is attached to a terminal (no piped input) and False when data is piped in.

Architectural Insights

The codebase follows a "plan is dominant noun" pattern, where plan operations are top-level commands. Commands are registered in cli.py using cli.add_command() with an explicit name= parameter. Commands receive ErkContext via the @click.pass_obj decorator and use it to access plan_store, git, and GitHub integrations. Error handling uses user_output() with a styled error prefix and the raise SystemExit(1) pattern. Schema V2 functions are located in erk_shared/github/metadata.py.

Domain Logic & Business Rules

The erk-plan label is required for all plan issues, and the command must ensure it exists before creating the issue. Title extraction follows a priority order: Explicit --title flag > First H1 > First H2 > First non-empty line > Error. Only one input source is allowed: either --file OR stdin, never both. TTY stdin without --file is an error. The worktree name is derived from the title and stored in the issue body metadata.

Known Pitfalls

Avoid using click.File() for stdin, as it doesn't work well with TTY detection. Use sys.stdin directly with the isatty() check instead. The H1 extraction regex must handle variations in whitespace. Use the GitHub integration directly, as the PlanStore ABC interface doesn't have a create_plan() method. Ensure the test file is located in the tests/commands/plan/ directory.

Testing Requirements

Run the following tests: uv run pytest tests/commands/plan/test_create.py, uv run pytest tests/commands/plan/, and uv run pyright src/erk/cli/commands/plan/create_cmd.py. Use erk_inmem_env() from tests/test_utils/env_helpers.py and build_workspace_test_context() from tests/test_utils/context_builders.py.

Error Handling Patterns

Follow the close_cmd.py pattern for error handling. Use LBYL for input validation before attempting operations.

Code Style Conventions

Use modern Python types (str | None), plain functions for commands, @click.pass_obj for context injection, explicit name= when registering commands, and user_output() for CLI output.

Rollback Considerations

Command registration is a single line in cli.py and easy to remove. The new file create_cmd.py and the new test file can be deleted. Documentation changes are additive and easy to revert.

Dependencies

Internal Dependencies:

  • erk_shared.github.metadata - format_plan_header_body(), format_plan_content_comment()
  • erk_shared.output.output - user_output()
  • erk.cli.core - discover_repo_context()
  • erk.core.context - ErkContext

External Dependencies:

  • click - CLI framework
  • sys - For stdin handling

Conclusion

In conclusion, the addition of the erk create command and the CLI organization documentation represents a significant enhancement to the usability and maintainability of our application. By providing a streamlined interface for creating GitHub issues and a clear, well-documented command structure, we empower users to more effectively manage and contribute to the project. This initiative aligns with our commitment to creating a user-friendly and efficient development environment. For more information on CLI design best practices, visit CLI Guidelines