Skip to content

Repository files navigation

Ch

License: MIT  Go 1.26.5+  Platform: macOS | Linux
Ch Stars  Cha Legacy Stars  IndexCh Companion Stars

Demo GIF

Table of Contents

Overview

Ch is a lightweight, GoLang-based CLI tool for AI interaction. As the successor to the now-deprecated Cha project, Ch delivers the same core functionality with over 10x faster startup and significantly improved performance. Ch prioritizes speed and efficiency, making it ideal for developers who need rapid AI interaction with minimal overhead and full user control.

Tip

Looking for semantic search across saved sessions? Check out the index_ch companion tool!

Vision

Ch provides direct terminal access to powerful AI models with minimal overhead, transparent operations, and explicit user control. It integrates seamlessly into developer environments, minimizing context switching and empowering users to leverage AI's full potential through explicit control and flexible, user-driven interactions without automated decisions or hidden costs.

Demo

Watch the full demo on YouTube (published on October 20, 2025) to see Ch in action with interactive chat, multi-platform switching, shell session recording, code export, and more. It demonstrates how Ch keeps a lightweight focused core while remaining powerful through integration with other CLI tools.

Quick Start

Install:

curl -fsSL https://raw.githubusercontent.com/MehmetMHY/ch/main/install.sh | bash

Configure:

export OPENAI_API_KEY="your-api-key-here"

Start using:

ch "What are the key features of Go programming language?"

Features

  • High Performance: Built for speed with minimal startup overhead
  • Multi-Platform Support: OpenAI, OpenRouter, Groq, DeepSeek, Anthropic, XAI, Together, Google Gemini, Mistral AI, Amazon Bedrock, and Ollama
  • Multi-Region Support: Switch between regional endpoints for platforms like Amazon Bedrock (22 AWS regions)
  • Interactive & Direct Modes: Chat interactively or run single queries
  • Unix Piping: Pipe any command output or file content directly to Ch
  • Seamless Pipe Output: Automatically suppresses colors and UI elements when output is piped, perfect for shell pipelines and automation
  • Smart File Handling: Load text files, PDFs, Word docs (DOCX/ODT/RTF), spreadsheets (XLSX/CSV), images (with OCR text extraction), and directories
  • Advanced Export: Interactive chat export with fzf selection and editor integration, with custom filename support (>custom) across all export and codedump flows
  • AI-Suggested Filenames: When exporting, the current model proposes short snake_case filenames based on chat context. Configurable and fully optional, with a graceful fallback to the deterministic hash-based names.
  • Code Block Export: Extract and save markdown code blocks with proper file extensions
  • Session State Viewer: Check current session details like model, platform, session file, and token usage
  • Token Counting: Estimate token usage for files or piped stdin with model-aware tokenization
  • Text Editor Integration: Use your preferred editor for complex prompts
  • Dynamic Switching: Change models and platforms mid-conversation
  • Smart Model Sorting: Model lists are sorted newest-first using API-provided timestamps, with alphabetical fallback for platforms that don't provide them
  • Chat Backtracking: Revert to any point in conversation history
  • Session Continuation: Automatically save and restore sessions to continue conversations later
  • Session History Search: Search and load any previous session from history with fuzzy or exact matching. Supports time-based filters (1d, 1w, 1m, 1y), epoch ranges, and direct session file loading. In interactive mode with save_all_sessions=true, continuing a loaded session forks it into a new timestamped session file so the original history remains unchanged. Ch also maintains a small latest-session pointer list so ch -c can continue from a recent timestamped session without scanning the full temp directory.
  • Code Dump: Package entire directories for AI analysis (text and document files only). Use -b/--build for an interactive fzf filename picker (new names via >custom) or an explicit name (ch -b ./src name.txt); use -y/--yes to skip all interactive fzf (auto-named, pipe-friendly)
  • Shell Session Recording: Record terminal sessions and provide them as context to the model
  • Web Scraping & Search: Built-in URL scraping and web search capabilities
  • Thinking/Reasoning Display: Shows model thinking tokens (reasoning) in gray before the response, supporting reasoning_content, reasoning (Ollama), and <think> tag formats. In streaming mode, thinking is display-only and is stripped from the saved final assistant response.
  • Clipboard Integration: Copy AI responses to clipboard with cross-platform support
  • Colored Output: Platform and model names displayed in distinct colors

Companion Search Tool

For deeper meaning-based search across saved Ch sessions, use index_ch, a companion/add-on tool that indexes local chat history and adds semantic search over past conversations. It exists for heavier archived-chat search, with fzf previews, multiprocessing, embeddings, and Groq-powered reranking, while staying separate so Ch can remain lightweight and focused.

Installation

curl -fsSL https://raw.githubusercontent.com/MehmetMHY/ch/main/install.sh | bash

Alternative methods:

# using wget
wget -qO- https://raw.githubusercontent.com/MehmetMHY/ch/main/install.sh | bash

# manual clone and install
git clone https://github.com/MehmetMHY/ch.git
cd ch
./install.sh

Uninstall:

# safe uninstall with confirmation prompt (recommended)
./install.sh --safe-uninstall

# or uninstall without confirmation
./install.sh --uninstall

The installer automatically:

  • Checks for Go 1.26.5+ and dependencies (fzf, yt-dlp, tesseract).
  • Installs missing dependencies via system package managers (apt, brew, pkg, etc.).
  • Builds and installs Ch to ~/.ch/bin/ch with temporary files in ~/.ch/tmp/.
  • Attempts to create a global symlink at /usr/local/bin/ch (or $PREFIX/bin/ch on Android/Termux).
  • If the symlink creation fails due to permissions, it will automatically install to ~/.ch/bin and provide instructions to add it to your PATH.
  • Gracefully handles missing tesseract development libraries by building without OCR support. If tesseract dev headers are missing, the app will still install and work normally, image-to-text extraction will simply be disabled.
  • When run from an existing local checkout, uses the current checkout as-is and does not run git pull automatically.

Configuration

API Keys

Set up API keys for your chosen platforms. OPENAI_API_KEY is required for AI requests when using the default openai platform, and BRAVE_API_KEY is required for the web search feature. Print-only utility commands such as ch -l file, ch -s URL, and ch -t file do not require an AI provider key unless you also provide a prompt to send the loaded content to a model.

Important Note on API Keys

By default, Ch uses the openai platform. If you run ch without setting the OPENAI_API_KEY, you will see an error. Here’s how to get started:

  1. Set the API Key: If you want to use OpenAI, set the environment variable:
    export OPENAI_API_KEY="your-openai-key"
  2. Switch Platforms: Use a different platform that you have configured. For example, to use Groq:
    ch -p groq "Hello"
  3. Use a Local Model: For a completely free and offline experience, use Ollama:
    ch -p ollama "Hello"
# commonly used
export OPENAI_API_KEY="your-openai-key"    # for the default OpenAI platform
export BRAVE_API_KEY="your-brave-api-key"  # for web search

# optional
export OPENROUTER_API_KEY="your-openrouter-key"
export GROQ_API_KEY="your-groq-key"
export DEEP_SEEK_API_KEY="your-deepseek-key"
export ANTHROPIC_API_KEY="your-anthropic-key"
export XAI_API_KEY="your-xai-key"
export TOGETHER_API_KEY="your-together-key"
export GEMINI_API_KEY="your-gemini-key"
export MISTRAL_API_KEY="your-mistral-key"
export AWS_BEDROCK_API_KEY="your-bedrock-key"

You can find links to obtain API keys below:

Platform Get API Key
OpenAI https://openai.com/api/
Brave Search https://brave.com/search/api/
OpenRouter https://openrouter.ai/settings/keys
Google Gemini https://ai.google.dev/gemini-api/docs/api-key
xAI https://x.ai/api
Groq https://console.groq.com/keys
Mistral AI https://docs.mistral.ai/getting-started/quickstart
Anthropic https://console.anthropic.com/
Together AI https://docs.together.ai/docs/quickstart
DeepSeek https://api-docs.deepseek.com/
Amazon Bedrock https://aws.amazon.com/bedrock/

Default Settings

Customize default platform and model via environment variables:

# default: openai
export CH_DEFAULT_PLATFORM="groq"

# default: gpt-5.4-mini
export CH_DEFAULT_MODEL="llama3-8b-8192"

Config File

For persistent configuration, create ~/.ch/config.json to override default settings without needing environment variables:

{
  "default_model": "grok-4-fast-non-reasoning",
  "current_platform": "xai",
  "preferred_editor": "vim",
  "show_search_results": true,
  "show_thinking": true,
  "num_search_results": 10,
  "search_country": "us",
  "search_lang": "en",
  "system_prompt": "You are a helpful assistant.",
  "slow_model_patterns": ["^o\\d+", "^gpt-5$"]
}

Available config options:

  • default_model - Set default model (automatically sets current_model if not specified)
  • current_model - Set current active model
  • current_platform - Set default platform
  • current_base_url - Set default base URL/region for multi-region platforms like Amazon Bedrock
  • preferred_editor - Set preferred text editor (default: "vim")
  • show_search_results - Show/hide web search results (default: true)
  • num_search_results - Number of search results to display (default: 5)
  • search_country - Set the country for web searches (default: "us")
  • search_lang - Set the language for web searches (default: "en")
  • system_prompt - Customize the system prompt
  • enable_session_save - Enable/disable automatic session saving for continuation (default: false)
  • save_all_sessions - Save all sessions with timestamps instead of overwriting the latest (default: false). When enabled, each session gets a unique timestamped file plus a small latest-session pointer list for fast ch -c; when disabled, only the latest session is kept
  • show_thinking - Show/hide model thinking/reasoning tokens (default: true). When enabled, thinking content is displayed in gray before the response. Supports reasoning_content, reasoning (Ollama), and <think> tag formats. In streaming mode, thinking is display-only and is stripped from the saved final assistant response.
  • slow_model_patterns - List of regex patterns for models that should use non-streaming mode with a loading animation (default: empty). Example: ["^o\\d+", "^gpt-5$"]
  • shallow_load_dirs - Directories to load with only 1-level depth for !l and !e operations (default: major system directories like /, /home/, /usr/, $HOME, etc.). Set to [] to disable.
  • ai_name_enable - Enable AI-suggested filenames in !e export modes (default: false). When true, the current model is asked to propose short snake_case filenames before each export filename prompt.
  • ai_name_char_threshold - Minimum non-system chat content (in characters) before AI-suggested filenames are generated (default: 500). Below this, the AI naming step is skipped.
  • ai_name_count - Number of AI-suggested filename candidates to request per export (default: 8).
  • ai_name_timeout_seconds - Cancel the AI naming request after this many seconds and fall back to the hash list (default: 15).
  • ai_name_prompt - Instruction sent to the model when generating filename suggestions. Use {count} as a placeholder for ai_name_count. The default asks for output as a single fenced text code block.
  • reasoning_effort - Default reasoning effort sent as root-level reasoning_effort in chat-completions requests (default: empty, which omits the parameter and preserves the provider default). Supported values are model-specific and discovered from Models.dev metadata. Example: "high"
  • reasoning_effort_switch - Interactive command key for reasoning effort selection (default: !r)
  • models_dev_enabled - Enable/disable Models.dev metadata lookups for reasoning-effort filtering (default: true). When false, !r shows generic unverified values instead of model-specific supported values
  • models_dev_refresh_hours - Cache refresh interval in hours for the Models.dev catalog (default: 24). Set to 168 for weekly refresh
  • compress_history - Interactive command key for compressing conversation history (default: !z)
  • compress_min_tokens - Minimum token count in the active context before !z will fire (default: 4000). Below this threshold compression is skipped
  • Plus all other configuration options using snake_case JSON field names

For a complete list of all configuration options and their defaults, see internal/config/config.go. Environment variables take precedence over the config file for default platform and model, while ~/.ch/config.json provides a convenient way to customize Ch without setting environment variables for each session.

Local & Open-Source Setup

Ch supports local models via Ollama, allowing you to run it without relying on third-party services. This provides a completely private, open-source, and offline-capable environment.

  1. Install Ollama: Follow the official instructions at ollama.com.

  2. Pull a model: ollama pull llama3

  3. Run Ch with Ollama: ch -p ollama "What is the capital of France?"

Since Ollama runs locally, no API key is required.

Usage

Basic Usage

# interactive mode
ch

# direct query
ch "Explain quantum computing"

# show version
ch -v
ch --version

# platform-specific query
ch -p groq "Write a Go function to reverse a string"

# model-specific query
ch -m gpt-4o "Create a REST API in Python"

# platform and model together
ch -o openai|gpt-4o "Create a REST API in Python"

# set reasoning effort for a single query
ch -r high "Explain recursion"
ch --reasoning-effort low "Quick summary"
ch -r default "Use the provider default effort"
ch -r medium -p google -m models/gemini-3.7-flash "hello"

# ask the model, then export code blocks from the response to files
ch -e "Write a Python script to sort a list"
ch --export "Write a Python script to sort a list"

# generate a codedump of a directory (auto-named, prints filename)
ch -d ./src

# same as above using the long-form flag
ch --dump ./src

# codedump with fzf filename picker (>custom for a new name, same as !e)
ch -b ./src

# codedump with an explicit output filename
ch -b ./src my_dump.txt

# codedump skipping all interactive fzf (include all files, auto-named)
# note: -y must come before positional args due to flag parsing order
ch -y -d ./src
ch -y -b ./src
ch -y -b ./src my_dump.txt

# load and display file content
ch -l document.pdf
ch -l document.docx  # or .odt, .rtf
ch -l spreadsheet.xlsx
ch -l screenshot.png

# scrape web content
ch -l https://example.com
ch -l https://youtube.com/watch?v=example

# count tokens in files
ch -t ./README.md
ch -m "gpt-4" -t ./main.go

# count tokens from piped stdin (no file path needed)
cat ./README.md | ch -t

# disable session saving for this run (only works if enable_session_save is true in config)
ch -n "What is AI?"
ch --no-history "Explain quantum computing"

# piping support (colors/UI automatically suppressed)
cat main.py | ch "What does this code do?"
echo "hello world" | ch "Translate to Spanish"
ls -la | ch "Summarize this directory"

# perfect for shell pipelines and automation
ch "list 5 fruits" | grep apple
ch "explain golang" > output.txt
ch -w "golang features" | head -10

# session continuation - requires enable_session_save=true
ch -c                              # continue last session interactively
ch -c "follow up question"         # continue with a new query
ch -c /path/to/history.json        # load custom history file and continue

# session history search - also requires save_all_sessions=true
ch -a                              # fuzzy search and load a previous session
ch -hs                             # same as -a (alias for --history)
ch -a exact                        # exact match search for previous sessions
ch -a 1w                           # filter sessions from the last week
ch -a 1776500000-1776542796        # filter sessions by epoch range
ch -a ch_session_latest.json       # load a specific session file directly
ch --clear                         # clear temporary files and sessions when session saving is enabled

# fetch a session into interactive mode
ch -f session.json                  # load session from current directory, or from ~/.ch/tmp/ if not found locally
ch -f /path/to/session.json        # load session by full path
ch -f                              # fzf pick from saved sessions (requires save_all_sessions=true)
ch -f session.json "query"         # load session then send a single query

When restoring a session, context-load summaries such as Loaded: notes.txt appear as standalone status lines. The user: label is reserved for user prompts.

Interactive Commands

When in interactive mode (ch), use these commands:

  • !q - exit interface
  • !h - help page
  • >state - help page option that shows current state. When session saving is active, it includes the session filename.
  • !c - clear chat history
  • !b - backtrack messages
  • !t [buff] - text editor mode
  • \ - multi-line mode (exit with \)
  • !m - switch models
  • !o - select from all models
  • !p - switch platforms
  • !r [effort] - set reasoning effort (or fzf pick if no argument). Use default to omit the parameter. Supported values are filtered per model using Models.dev metadata
  • !l [dir] - load files/dirs
  • !a [filter] - search and load sessions (filters: 1d, 1w, 1m, 1y, exact, , ). With save_all_sessions=true, new messages after !a are saved to a new forked session file instead of overwriting the loaded one.
  • !x / ! - record shell session; run a command with !x cmd, ! cmd, or !cmd (no space)
  • !!x / !! - record shell session (output not saved to history); run a command with !!x cmd, !! cmd, or !!cmd (no space)
  • !s [url] - scrape URL(s) or from history
  • !w [query] - web search or from history
  • !d - generate codedump
  • !z - compress conversation history. Summarizes the active context into a dense continuation summary, reducing token usage for future prompts while preserving the full transcript for exports, search, and session files. Uses map-reduce chunking for oversized conversations with parallel summarization. Ctrl+C cancels safely without mutating state
  • !e [file] - export chat(s). Surrounding quotes ("/') are stripped, so !e "hi.txt" saves as hi.txt
  • !y - add to clipboard
  • cc - quick copy latest response
  • ctrl+c - clear prompt input. At a custom export filename prompt, cancels the export and returns to interactive mode.
  • ctrl+d - exit completely

Advanced Features

Code Export (-e flag):

  • Automatically detects programming languages
  • Saves with proper file extensions
  • Supports 25+ languages and file types

Interactive Export (!e and !e [file]):

Offers three modes for exporting chat history:

  1. turn export: Select individual user prompts and bot responses to export. Uses >all option to quickly select everything. Opens editor for final review before saving.
  2. block export: Extracts all code blocks from your entire chat history. Lets you save each snippet individually, intelligently suggesting file names and extensions based on the code's language and content. Presents a prioritized list of suggested new names and existing files (marked with [w] for overwrite).
  3. manual export: Allows you to select specific chat entries, which are then combined into a single file for you to edit and save manually. Also benefits from the smart file-saving interface.

Optional: Provide a filename (!e output.txt) to skip the file selection step and save directly to that file.

Custom Filenames:

Every filename selection step in the export flows (turn, block, manual, and -e/--export code blocks) supports entering a custom name via the >custom sentinel:

  • >custom: Select the >custom entry at the top of the fzf list, then type a filename when prompted and press Enter. Press Ctrl+C or Ctrl+D at the filename prompt to cancel the export and return to interactive mode.
  • Enter: Selects/overwrites the highlighted list item. This is how you overwrite an existing file (files already in the directory are listed and marked [w]).

New filenames are entered only through >custom; typing a query that matches nothing cancels the export instead of creating a file, so a fuzzy near-match never silently overwrites the wrong file. Custom names preserve spaces, uppercase, dots, and dashes as typed; path separators (/) are stripped so the file stays in the current directory. No extension is auto-appended, so include one if you want one (e.g. my notes.txt). Blank filename input, Ctrl+C, and Ctrl+D cancel the export without exiting Ch. When a filename is passed directly to !e, surrounding quotes are stripped (!e "hi.txt" saves as hi.txt).

AI-Suggested Filenames:

When you reach a filename selection step in any !e export mode, Ch asks the currently selected model to propose a few short, snake_case filenames that summarize what's being saved. The model receives the full chat history plus the content being exported, so the suggestions are context-aware. AI suggestions appear at the top of the fzf list (always with a .txt extension), followed by the regular ch_<hash>.<ext> options and existing files in the directory.

Behavior notes:

  • A spinner ("Loading...") is shown while the model responds. Pressing Ctrl+C aborts the export, matching how other spinners behave in Ch.
  • If the chat history is short (default: under 500 characters of non-system content), AI naming is skipped automatically. There isn't enough context for useful names yet.
  • If the model takes longer than the configured timeout (default 15 seconds) to respond, the request is cancelled and Ch falls back to the hash-based list.
  • If the model fails, returns nothing usable, or AI naming is disabled, Ch silently falls back to the existing hash-based filename list.
  • Output is parsed from a fenced code block tagged text for reliable extraction across providers, and each name is sanitized (lowercase, [a-z0-9_] only, deduped, capped at 40 characters).

Configurable via ~/.ch/config.json. Example showing how to enable AI naming with all available keys:

{
  "ai_name_enable": true,
  "ai_name_char_threshold": 500,
  "ai_name_count": 8,
  "ai_name_timeout_seconds": 15,
  "ai_name_prompt": "Based on the conversation above, propose {count} short filenames that best summarize what's being saved.\n\nRules for each name:\n- lowercase only\n- words separated by underscores\n- 1 to 4 words per name\n- no file extension\n- no punctuation, no quotes, no spaces, no commentary\n\nOutput format: respond with EXACTLY one fenced code block tagged \"text\", containing one filename per line and nothing else. Example:\n\n```text\nhello_world\napi_request_handler\nparse_json\n```\n\nDo not include any text before or after the code block."
}

AI-suggested filenames are disabled by default. Set ai_name_enable to true in your config to enable them. Use {count} as a placeholder in ai_name_prompt to substitute ai_name_count at request time.

URL Scraping (!s and -l with URLs):

  • Supports regular web pages and YouTube videos
  • Extracts clean text content from web pages using a built-in parser
  • YouTube videos include metadata and subtitle extraction via yt-dlp. Subtitles are compacted (cue numbers, milliseconds, and blank lines stripped; >> speaker markers preserved) to reduce token usage without losing transcript content.
  • Multiple URL support: !s https://site1.com https://site2.com
  • Interactive URL selection: When called without arguments (!s), scans chat history for all URLs, removes duplicates, and presents them via fzf for multi-selection with tab key
  • Integrated with file loading: ch -l https://example.com

Web Search (!w):

  • Built-in Brave Search integration via the Brave Search API
  • Requires BRAVE_API_KEY to be set in your environment variables
  • Usage: !w "search query" or !w to select a sentence from chat history
  • Results are automatically added to conversation context
  • No need for external tools, but requires an API key

Clipboard Copy (!y):

  • Four copy modes: turn copy (select individual prompts and responses), block copy (extract code blocks), manual copy (select responses with editor), link copy (select URLs)
  • Use >all option at the top of any list to quickly select everything
  • Edit content in your preferred editor before copying (manual mode)
  • Cross-platform clipboard support (macOS, Linux, Android/Termux, Windows)
  • Usage: !y then select mode and items to copy

Web Content Interaction

The -s and -w flags in the terminal CLI are used for web content interaction:

-s flag (Scrape URL)

  • Usage: ch -s <URL>
  • Function: Scrapes content from the specified URL.
  • Supports scraping normal web pages and YouTube videos.
  • For normal web pages, it fetches and extracts clean text content from the HTML.
  • For YouTube URLs, it uses yt-dlp to extract metadata and subtitles. Subtitles are compacted to reduce token usage (cue numbers, milliseconds, and blank lines removed; >> speaker markers preserved).
  • Quote YouTube URLs in your shell: ch -s 'https://www.youtube.com/watch?v=OHiKsF0JXPk'.
  • If subtitle downloading fails, metadata is still printed with a Subtitles unavailable diagnostic from yt-dlp. An HTTP 429 means YouTube is rate-limiting requests from your connection; wait before retrying. Missing English SRT subtitles and empty subtitle files are also reported explicitly. Ch does not transcribe the audio when subtitles are unavailable.
  • The scraped content is printed directly to the terminal.

-w flag (Web Search)

  • Usage: ch -w <search query>
  • Function: Performs a web search using the Brave Search API.
  • Requires BRAVE_API_KEY environment variable to be set.
  • Fetches search results from Brave Search.
  • Prints the formatted search results (title, URL, description) to the terminal.

Both commands help in integrating external web content and search results into CLI workflow with Ch.

Platform Compatibility

Ch supports multiple AI platforms with seamless switching:

Platform Models Environment Variable Regions/Endpoints
OpenAI GPT-4o, GPT-4o-mini, etc. OPENAI_API_KEY 1
OpenRouter Various models OPENROUTER_API_KEY 1
Groq Llama3, Mixtral, etc. GROQ_API_KEY 1
DeepSeek DeepSeek-Chat, etc. DEEP_SEEK_API_KEY 1
Anthropic Claude-3.5, etc. ANTHROPIC_API_KEY 1
xAI Grok models XAI_API_KEY 1
Together Serverless chat models TOGETHER_API_KEY 1
Google Gemini models GEMINI_API_KEY 1
Mistral Mistral-tiny, small, etc. MISTRAL_API_KEY 1
Amazon Bedrock Claude, Llama, Mistral, etc AWS_BEDROCK_API_KEY 22
Ollama Local models (Llama3, etc) (none) 1

Switch platforms during conversation:

!p groq
!p anthropic
!m gpt-4o

Multi-Region Platforms:

Some platforms like Amazon Bedrock support multiple regions. When switching to a multi-region platform, you'll be prompted to select a region before choosing a model:

!p amazon
# Prompts: region: (select from 22 AWS regions)
# Prompts: model: (select from available models in that region)

Supported AWS Bedrock regions: US East (N. Virginia, Ohio), US West (Oregon), Asia Pacific (Tokyo, Seoul, Osaka, Mumbai, Hyderabad, Singapore, Sydney), Canada (Central), Europe (Frankfurt, Ireland, London, Milan, Paris, Spain, Stockholm, Zurich), South America (São Paulo), and AWS GovCloud (US-East, US-West).

Website

The project website is hosted on GitHub Pages at: https://mehmetmhy.github.io/ch/

The website source is located in the docs/ directory. To run the website locally, you need Python 3 installed. Run the server with either of the following commands:

cd docs
./run.py
# or
python3 run.py

The server starts on port 8000 by default. If that port is taken, it automatically tries the next available port up to 8099. Press Ctrl+C or Ctrl+D to stop the server.

The landing page includes an animated terminal preview that plays a multi-scene tour of common Ch workflows (direct prompts, pipes, file/URL/web loading, YouTube scraping, codedump, provider/model switching, interactive commands, export, and continuation). It auto-follows while animating, supports manual scrolling, lets you click a command line to copy it, and degrades to fully readable static text without JavaScript.

Development

Contributor and coding-agent guidance is available in AGENTS.md.

Prerequisites

Instead of installing gosec, Gitleaks, and govulncheck by hand, you can run ./install.sh --dev-setup once to install all three security tools and activate the fast pre-commit hook in a single step.

Build from Source

git clone https://github.com/MehmetMHY/ch.git

cd ch

# build locally without installing
./install.sh -b

Build Options

# using the install script (local build options)
./install.sh -b     # build locally without installing
./install.sh -r -b  # refresh/update all dependencies and build
./install.sh -v     # update version in Makefile interactively
./install.sh -c     # run unit tests with a pass/fail summary
./install.sh -k     # run gosec, gitleaks, and govulncheck with a pass/fail summary
./install.sh -d     # dev setup: install security tools and activate the fast pre-commit hook
./install.sh -h     # show help with all options

# using Make directly
make install  # install to $GOPATH/bin
make clean    # clean build artifacts
make test     # run tests
make lint     # run linter
make fmt      # format code
make security # run gosec and govulncheck
make verify   # full gate: fmt, vet, tests, security (portable, CI-agnostic)
make install-hooks # enable the local pre-commit hook (fmt-check + staged gitleaks)
make dev      # build and run in dev mode

Testing

Run all tests:

make test

Quick pass/fail summary via the install script:

./install.sh -c

Per-function coverage report:

go test -coverprofile=/tmp/cover.out ./... && go tool cover -func=/tmp/cover.out

Test the installer on a clean machine (requires Docker):

./.install_test.sh

.install_test.sh builds a minimal Ubuntu image with only Go pre-installed, then runs the real curl | bash install command inside a throwaway container and reports pass/fail. Installer progress is streamed live; the fresh dependency installation and build can take several minutes. This verifies the end-to-end install flow without touching your own system.

Security Checks

Local security checks use gosec for source scanning, Gitleaks for secret scanning, and govulncheck for known Go vulnerabilities.

Install gosec once:

go install github.com/securego/gosec/v2/cmd/gosec@latest

Install Gitleaks once:

brew install gitleaks

Run the checks:

make security-static   # gosec ./...
make security-secrets  # gitleaks git --no-banner --redact .
make security-secrets-working # gitleaks dir --no-banner --redact .
make security-vuln     # go mod verify + govulncheck ./...
make security          # all checks
make verify            # full gate: fmt-check, vet, tests, and security

make verify bundles the entire quality gate into one portable command. It is intentionally provider-agnostic: any executor (a self-hosted runner or a manual pre-merge check) can run make verify without tying the project to a specific CI vendor.

make build runs security-static before compiling. To set up local development in one step (install gosec, gitleaks, and govulncheck, then activate the fast pre-commit hook):

./install.sh --dev-setup
git config --get core.hooksPath  # should print .githooks

If you only want to activate the pre-commit hook (and already have the tools installed), you can run make install-hooks directly instead.

The pre-commit hook runs only fast checks to keep commits snappy (~1s total):

  • pre-commit runs fmt-check and staged-change Gitleaks scanning before allowing a commit.

The previous heavy pre-commit checks (unit tests, gosec, working-tree Gitleaks) and the pre-push hook (govulncheck) have been removed to keep day-to-day development fast. For on-demand deep security checks, run:

./install.sh --security
# or
./install.sh -k

This runs gosec, gitleaks (committed history + working tree), and govulncheck in sequence and prints a combined pass/fail summary.

Git hooks are local Git configuration, so they are not activated just by cloning the repository. Run ./install.sh --dev-setup (or make install-hooks) once in each checkout where you want commits to be blocked by the fast security gate.

For secret testing, stage the file first and run the staged scanner:

git add --all
make security-secrets-staged

If the file was already committed and the staged change is only a rename or mode change, the staged diff can be empty. Run the working-tree scanner for that case:

make security-secrets-working

gitleaks git . scans committed history, not arbitrary untracked working-tree files, so it will not catch a newly created file until it is staged or committed. gitleaks dir . scans the current checkout.

When using ./install.sh -b for a local repository build, the installer checks the development security tools required by make build: it installs gosec with go install if missing, installs Gitleaks via Homebrew on macOS when possible, and otherwise prints manual Gitleaks install guidance.

Version Management

Check the installed version:

ch -v
ch --version

This prints ch <version> and exits before any provider or config initialization, so it works without an API key.

Update the project version interactively:

./install.sh -v

This will:

  • Display the current version from Makefile
  • Offer semantic version bump options (patch, minor, major)
  • Allow custom version input
  • Update the VERSION in Makefile automatically

The Makefile VERSION line is the single source of truth. Both make build and the installer's direct go build path inject the same ldflags, so curl|bash and make-built binaries report the same version. A raw go build without ldflags reports the dev fallback.

Contributing

Contributions are welcome! Here's how to get started:

  1. Report Issues: Open an issue for bugs or feature requests
  2. Submit Pull Requests: Fork, make changes, and submit a PR
  3. Improve Documentation: Help enhance README, examples, or guides

Development Setup

git clone https://github.com/MehmetMHY/ch.git

cd ch

# refresh dependencies and build
./install.sh -r -b

# install security tools and activate the fast pre-commit hook
./install.sh --dev-setup

make dev

Code Standards

  • Follow existing Go conventions
  • Run make fmt and make lint before submitting
  • Test your changes thoroughly
  • Update documentation as needed
  • To add new slow models, add regex patterns to slow_model_patterns in ~/.ch/config.json
  • To set a default reasoning effort, add reasoning_effort to ~/.ch/config.json (e.g. "reasoning_effort": "high")

Uninstall

Use --safe-uninstall for a confirmation prompt before deletion (recommended). Both uninstall modes remove ~/.ch, including config, history, sessions, and temporary files. The --uninstall flag deletes immediately without confirmation.

# safe uninstall with confirmation prompt (recommended)
./install.sh --safe-uninstall

# or uninstall without confirmation
./install.sh --uninstall

Manual uninstall:

# manual uninstall for Unix-based systems
sudo rm -f /usr/local/bin/ch
rm -rf ~/.ch

# manual uninstall for Android/Termux systems
rm -f $PREFIX/bin/ch
rm -rf ~/.ch

Clean Temporary Files

If you want to safely remove all Ch temporary files without uninstalling the application:

[ -d "${HOME}/.ch/tmp/" ] && rm -rf "${HOME}/.ch/tmp/"

This is useful for reclaiming disk space if temporary files from shell sessions, file loads, or other operations have accumulated.

The Models.dev metadata cache is stored at ~/.ch/cache/ and can be safely removed if needed. Ch will re-fetch it on the next !r or -r action:

[ -d "${HOME}/.ch/cache/" ] && rm -rf "${HOME}/.ch/cache/"

License

Ch is licensed under the MIT License. See LICENSE for details.

About

Lightweight, fast, & powerful CLI tool for terminal-based AI interactions with full user control

Resources

Stars

31 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages