From dd8bcbef54ed7a72cee8a929ccb8602c4c8a3a13 Mon Sep 17 00:00:00 2001 From: Juan Olvera Date: Mon, 21 Jul 2025 15:53:02 -0500 Subject: [PATCH 1/6] feat: add custom headers for openrouter api requests --- internal/agents/reviewer.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/agents/reviewer.go b/internal/agents/reviewer.go index d50cbb0..a77178b 100644 --- a/internal/agents/reviewer.go +++ b/internal/agents/reviewer.go @@ -37,11 +37,18 @@ 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": "https://github.com/j0lvera/miso", + "X-Title": "miso", + } + // 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.WithSetCustomHeader(headers), ) if err != nil { return nil, fmt.Errorf( From ab383e6c496ce73377bf0ac41a2710475d3ec527 Mon Sep 17 00:00:00 2001 From: Juan Olvera Date: Mon, 21 Jul 2025 15:55:40 -0500 Subject: [PATCH 2/6] refactor: extract website and name into constants --- internal/agents/reviewer.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/agents/reviewer.go b/internal/agents/reviewer.go index a77178b..f64a964 100644 --- a/internal/agents/reviewer.go +++ b/internal/agents/reviewer.go @@ -12,6 +12,11 @@ import ( "github.com/tmc/langchaingo/llms/openai" ) +const ( + website = "https://github.com/j0lvera/miso" + name = "miso" +) + // 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 { @@ -39,8 +44,8 @@ func NewCodeReviewer() (*CodeReviewer, error) { // Set custom headers for OpenRouter headers := map[string]string{ - "HTTP-Referer": "https://github.com/j0lvera/miso", - "X-Title": "miso", + "HTTP-Referer": website, + "X-Title": name, } // Configure for OpenRouter From 83b7d65059de01ac04ed5170d4d575ed2b4c0239 Mon Sep 17 00:00:00 2001 From: Juan Olvera Date: Mon, 21 Jul 2025 16:22:06 -0500 Subject: [PATCH 3/6] docs: add changelog entry for openrouter header refactor --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be1ea50..bc44ffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. From 77f5c7ce8f3b5155ae2dab52f3c5fdeedfbaceaf Mon Sep 17 00:00:00 2001 From: Juan Olvera Date: Mon, 21 Jul 2025 18:58:40 -0500 Subject: [PATCH 4/6] guides: add cli --- guides/cli-guidelines-long.md | 130 +++++++++++++++++++++++++++++++++ guides/cli-guidelines-short.md | 19 +++++ 2 files changed, 149 insertions(+) create mode 100644 guides/cli-guidelines-long.md create mode 100644 guides/cli-guidelines-short.md diff --git a/guides/cli-guidelines-long.md b/guides/cli-guidelines-long.md new file mode 100644 index 0000000..e48cc69 --- /dev/null +++ b/guides/cli-guidelines-long.md @@ -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. \ No newline at end of file diff --git a/guides/cli-guidelines-short.md b/guides/cli-guidelines-short.md new file mode 100644 index 0000000..d48b577 --- /dev/null +++ b/guides/cli-guidelines-short.md @@ -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  . \ No newline at end of file From d4af3505104043038569ec28a4bdb159e73381b9 Mon Sep 17 00:00:00 2001 From: Juan Olvera Date: Mon, 21 Jul 2025 19:23:59 -0500 Subject: [PATCH 5/6] feat: use custom http client for openrouter headers --- internal/agents/reviewer.go | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/internal/agents/reviewer.go b/internal/agents/reviewer.go index f64a964..39adfc2 100644 --- a/internal/agents/reviewer.go +++ b/internal/agents/reviewer.go @@ -3,6 +3,7 @@ package agents import ( "context" "fmt" + "net/http" "os" "github.com/j0lvera/miso/internal/config" @@ -17,6 +18,21 @@ const ( 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 { @@ -44,8 +60,19 @@ func NewCodeReviewer() (*CodeReviewer, error) { // Set custom headers for OpenRouter headers := map[string]string{ - "HTTP-Referer": website, - "X-Title": name, + "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 @@ -53,7 +80,7 @@ func NewCodeReviewer() (*CodeReviewer, error) { openai.WithToken(apiKey), openai.WithBaseURL("https://openrouter.ai/api/v1"), openai.WithModel("anthropic/claude-3.5-sonnet"), - openai.WithSetCustomHeader(headers), + openai.WithHTTPClient(client), ) if err != nil { return nil, fmt.Errorf( From 100615118ab2f1ed1588655385bbc735afd7f032 Mon Sep 17 00:00:00 2001 From: Juan Olvera Date: Mon, 21 Jul 2025 19:39:09 -0500 Subject: [PATCH 6/6] fix: use http-referer header for openrouter compatibility --- internal/agents/reviewer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/agents/reviewer.go b/internal/agents/reviewer.go index 39adfc2..1b156f4 100644 --- a/internal/agents/reviewer.go +++ b/internal/agents/reviewer.go @@ -60,8 +60,8 @@ func NewCodeReviewer() (*CodeReviewer, error) { // Set custom headers for OpenRouter headers := map[string]string{ - "Referer": website, - "X-Title": name, + "HTTP-Referer": website, + "X-Title": name, } // Create a custom transport to add headers