Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- Refactor OpenRouter headers to use constants.

## [0.3.2] - 2025-07-22
### Fixed
- Use `amd64` for x86_64 architecture in `install.sh` to match GoReleaser artifacts.
Expand Down
130 changes: 130 additions & 0 deletions guides/cli-guidelines-long.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
1. Human-First Design

Your users are humans first. Write output and error messages that are helpful and natural, not cryptic or overly technical. Prioritize clear communication over terse syntax. Provide usage examples, suggest next steps, and treat the CLI as a conversation with your user.

2. Do One Thing Well

Follow the UNIX tradition of building tools that are good at one job. Avoid overloading a single CLI with too many responsibilities. Use subcommands (like git commit) to structure related tasks clearly, and offload complex logic to underlying libraries or services.

3. Compose with Others

Design your tool to work well in pipelines. Support piping input from stdin and writing to stdout, and offer structured output like JSON or CSV when appropriate. Respect the CLI ecosystem’s strengths—small programs that work together seamlessly.

4. Consistency over Cleverness

Conventions exist for a reason. Use standard flags like --help, --version, -v for verbose, -q for quiet, etc. Familiarity breeds confidence: users should be able to guess how your tool works based on experience.

5. Say Just Enough

Avoid noisy default output. Don’t print debug logs unless explicitly asked. Show only what the user needs, and let them ask for more via --verbose or --debug. Clean output makes tools easier to read and parse.

6. Support Discovery

Make your tool easy to explore. Provide clear help output (--help), usage examples, and even interactive or auto-generated help if needed. Good error messages should guide the user, not just report failure.

7. Be Empathetic

Consider what users will misunderstand or get wrong—and help them recover gracefully. Catch common mistakes. Suggest spelling corrections. Offer clear, constructive error messages. Be kind. A CLI should never feel like it’s scolding the user.

8. Innovate Intentionally

Don’t be afraid to break convention if it truly improves UX—but do so thoughtfully and with clear documentation. Innovation should reduce cognitive load, not increase it.

🧪 Practical Guidelines

✅ Use a Robust Argument Parser

Use a battle-tested CLI argument parser for your language (e.g., argparse in Python, cobra in Go, commander in Node). Avoid hand-rolling unless absolutely necessary. These libraries provide built-in support for help text, validation, default values, and type coercion—saving time and reducing bugs.

📜 Help and Usage Output

Ensure --help or -h always works. Your help output should:
• Be readable without scrolling (unless the command is complex).
• Include a brief description of the tool and each argument.
• Provide practical examples of real-world usage.
• Mention exit codes or behavior under failure modes if relevant.

For complex tools, subcommands should each have their own --help output.

🧹 Minimal Output by Default

Design your tool to behave like UNIX tools:
• Quiet on success (unless there’s valuable output).
• Print only the essentials.
• Use --verbose or --debug to show progress bars, timestamps, or internal logic.

This approach makes your CLI composable, scriptable, and easier to automate.

📦 Structured Output

Provide machine-readable output via flags like --json or --csv. This allows your tool to be used in scripts, pipelines, and dashboards. Don’t just dump repr() strings—format the data cleanly and consistently.

Where possible:
• Pretty-print JSON for humans.
• Compact-print JSON for machines (jq-friendly).
• Consider TOML or YAML when config-like data is output.

📘 Paging for Long Output

Use a pager like less or more for lengthy output (e.g., logs, diffs, help text), especially when it exceeds one terminal screen. Let users opt out via --no-pager or similar.

❌ Handle Errors Gracefully

Don’t expose raw stack traces by default. Catch common errors (e.g., file not found, permission denied) and rephrase them clearly:
• “Error: config.toml not found. Did you forget to run init?”
• “Permission denied. Try running with sudo or check file ownership.”

Exit codes should follow conventions:
• 0: success
• 1: general error
• 2: misuse of CLI (bad flags, invalid args)
• 126: permission denied
• 127: command not found

You can also print helpful suggestions after errors—think of how Git does this.

🔠 Naming Conventions

Pick a short, lowercase, memorable name. Avoid collisions with existing tools. Consider namespacing subcommands if appropriate (mycli deploy, mycli config set). Avoid generic or overloaded terms like tool, cmd, cli.

If you expect your CLI to be installed globally, check popular tools like Homebrew or apt to avoid name conflicts.

📦 Installation & Distribution

Make installation easy. Ideally:
• Provide a single static binary or a shell script install method.
• Include version information (--version).
• Publish on package managers (e.g., pip, npm, brew, cargo, apt, etc.).
• Provide signed or checksummed releases to improve security and trust.

Avoid bloated installs or large dependency trees. The smaller, the better.

👀 Transparency & Analytics

If your tool collects telemetry:
• Make it opt-in, not opt-out.
• Explain what you collect and why.
• Offer a --no-analytics or env var override.
• Honor privacy by default.

Users should never feel spied on by a CLI.

🪜 Implementation Checklist

Here’s a quick checklist you can use when launching or auditing your CLI project:
• Uses standard --help, --version, --verbose flags
• Quiet on success, with --verbose for more detail
• Error messages are human-friendly and suggest next steps
• Offers --json or similar for structured output
• Supports stdin/stdout and can be composed with other tools
• Has paginated output when helpful
• Written with a real CLI parser (not hand-rolled)
• Has clear, up-to-date help text and usage examples
• Follows exit code conventions
• Installs easily with minimal dependencies
• Doesn’t collect analytics without consent

🎯 Conclusion

Great CLI tools are invisible: they do their job efficiently, predictably, and helpfully. They don’t frustrate, confuse, or overwhelm. Instead, they guide users, respect conventions, and offer small delights—like helpful error suggestions or polished output.
By following the Command-Line Interface Guidelines, you’re building more than a tool—you’re designing a conversation between your program and the person using it. Done well, it becomes second nature to the user. It feels familiar from the first use. That’s the power of great CLI design.
19 changes: 19 additions & 0 deletions guides/cli-guidelines-short.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
The CLI Guidelines are an open‑source effort, grounded in UNIX philosophy and revised for today’s human-first command lines . They weave together practical best practices with design principles to help developers build intuitive, robust, and composable CLI tools.

Philosophy & Design Principles:
• Human‑First Design: Tailor your CLI primarily for human users—clear messages, intuitive syntax .
• Simple, Composable Tools: Create focused commands that work well together via pipes, standard I/O, and structured outputs like JSON .
• Consistency & Predictability: Follow established conventions (flags, syntax, exit codes) so users can reliably guess behavior .
• Say Just Enough: Balance verbosity—provide useful feedback without overwhelming users .
• Discovery & Conversation: Offer helpful --help, usage examples, error suggestions, and next‑step guidance—mirroring a conversational flow .
• Empathy & Delight: Show users you’ve considered their needs—clear error corrections, supportive tone, even tasteful embellishments .
• Intentional Innovation (“Chaos”): Feel free to break norms—but only when it improves usability, and do it deliberately .

Practical Guidelines:
1. Argument Parsing: Use reliable libraries; auto-generate help, usage, and spell-check flags .
2. Minimal Default Output: Avoid developer-centric logs—reserve detailed feedback for verbose mode .
3. Structured Output & Paging: Provide JSON or machine-readable output modes; use pagers like less for long output streams .
4. Error Handling: Catch errors early; rephrase in human-friendly terms with guidance (e.g., chmod suggestions) .
5. Naming: Choose concise, lowercase, memorable command names; avoid overly generic names to prevent confusion .
6. Distribution: Aim for single-file or minimal-dependency releases; bundle cleanly to simplify installation .
7. Analytics: If collecting metrics, do so transparently and give users control, ideally via opt‑in flags  .
39 changes: 39 additions & 0 deletions internal/agents/reviewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package agents
import (
"context"
"fmt"
"net/http"
"os"

"github.com/j0lvera/miso/internal/config"
Expand All @@ -12,6 +13,26 @@ import (
"github.com/tmc/langchaingo/llms/openai"
)

const (
website = "https://github.com/j0lvera/miso"
name = "miso"
)

// headerTransport is a custom http.RoundTripper to add headers to requests.
type headerTransport struct {
base http.RoundTripper
headers map[string]string
}

// RoundTrip adds custom headers to the request before sending it.
func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req2 := req.Clone(req.Context())
for k, v := range t.headers {
req2.Header.Set(k, v)
}
return t.base.RoundTrip(req2)
}

// ReviewResult holds the review content and token usage information from an LLM call.
// Provides details about the review content and associated costs.
type ReviewResult struct {
Expand All @@ -37,11 +58,29 @@ func NewCodeReviewer() (*CodeReviewer, error) {
return nil, fmt.Errorf("OPENROUTER_API_KEY environment variable is not set")
}

// Set custom headers for OpenRouter
headers := map[string]string{
"HTTP-Referer": website,
"X-Title": name,
}

// Create a custom transport to add headers
transport := &headerTransport{
base: http.DefaultTransport,
headers: headers,
}

// Create a custom HTTP client
client := &http.Client{
Transport: transport,
}

// Configure for OpenRouter
llm, err := openai.New(
openai.WithToken(apiKey),
openai.WithBaseURL("https://openrouter.ai/api/v1"),
openai.WithModel("anthropic/claude-3.5-sonnet"),
openai.WithHTTPClient(client),
)
if err != nil {
return nil, fmt.Errorf(
Expand Down
Loading