{"id":17527043,"url":"https://github.com/dnmfarrell/ch","last_synced_at":"2025-04-14T11:16:48.437Z","repository":{"id":187329798,"uuid":"676715818","full_name":"dnmfarrell/ch","owner":"dnmfarrell","description":"Program ChatGPT from a POSIX shell","archived":false,"fork":false,"pushed_at":"2024-05-20T18:56:50.000Z","size":28,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-05-20T22:16:07.363Z","etag":null,"topics":["chatgpt","openai","perplexity","posix-shell"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dnmfarrell.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-09T20:58:27.000Z","updated_at":"2024-05-20T21:00:25.000Z","dependencies_parsed_at":"2024-05-20T20:34:58.872Z","dependency_job_id":"ac3bf1b8-fbf0-4e56-b571-e107ef6b72eb","html_url":"https://github.com/dnmfarrell/ch","commit_stats":null,"previous_names":["dnmfarrell/ch"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnmfarrell%2Fch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnmfarrell%2Fch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnmfarrell%2Fch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnmfarrell%2Fch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dnmfarrell","download_url":"https://codeload.github.com/dnmfarrell/ch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224867731,"owners_count":17383086,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatgpt","openai","perplexity","posix-shell"],"created_at":"2024-10-20T15:03:00.868Z","updated_at":"2025-04-14T11:16:48.421Z","avatar_url":"https://github.com/dnmfarrell.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"Chat Shell Script\n---\n`ch` is a POSIX-compliant shell script. It's a minimal framework around cURL to make it convenient to use chat completion models from the terminal:\n- Access chat completion APIs from your terminal, no more context switching to browser tabs.\n- Each conversation is stored in its own local file for easy replay, re-transmission etc.\n- Integrate chat requests with standard shell tools like pipes, redirects and grep.\n- Source `ch` in your own shell scripts to use it as a library. See `tests/run.sh` for an example.\n\nWorks with OpenAI, Anthropic, DeepSeek and Perplexity APIs.\n\n### System Requirements\n1. An operating system with a POSIX-compatible shell. Tested on: Linux, MacOS, BSD, Android (via Termux).\n2. A valid API key. Create one at OpenAI, Perplexity, DeepSeek ...\n3. The utilities curl and jq to be installed.\n\n### Usage\n    ch [Option]\n    \n    Options\n      a|again            in case of error, send current chat again\n      c|current \u003cID\u003e     switch the current chat to a differerent ID\n      h|help             print this help\n      i|id               print the current chat ID\n      p|print            print out the current chat\n      l|list             list all chat IDs\n      n|new \u003cprompt\u003e     start a new chat\n      r|reply \u003creply\u003e    reply to the current chat\n      s|source           print out the current chat raw json source\n    \n      Arguments in \u003cangle brackets\u003e are read from STDIN if not present.\n\n### Example\n    $ ./ch n is it possible to '\"delete\"' lines of output in a terminal, or simulate it using ANSI escape sequences?\n    Yes, it is possible to \"delete\" lines of output in a terminal or simulate it using ANSI escape sequences.\n    \n    Here's an example of how you can simulate deleting lines in a terminal using ANSI escape sequences in Python:\n    ...\n    $ ./ch r show me how to do it with bash shell code\n    ...\n\nAll chats are stored in their own JSON line file under CH_TMP. The basename of each file is its unique chat ID. The `list` command lists all these files:\n\n    $ ./ch l\n    /tmp/chgpt/20250122204649.307857\n    /tmp/chgpt/20250205094326.769195\n    /tmp/chgpt/20250207145459.836016\n    /tmp/chgpt/20250208105540.843291\n\nBecause chats are files, they can be read, grepped, piped and generally manipulated with standard shell tools.\n\nThe file `$CH_TMP/.cur` is a history of all chat IDs, one per line. When a chat is created, its ID is appended to .cur. The last ID in .cur is the current chat. It can be changed with the `current` command:\n\n    $ ./ch c 20250122204649.307857\n\nBut chat IDs are kind of opaque, so I often grep chats to find the one I want to switch back to:\n\n    $ grep -li 'prolog variable' $(./ch l) | xargs basename | ./ch c\n    $ ch p\n    Is prolog variable unification scoped by disjunctive branches within the same goal?\n    In Prolog, variable unification is indeed scoped by disjunctive branches within the same goal.\n    ...\n\n### Environment Variables\nManipulate these to tune the behavior of `ch`. Default values are shown (in parens).\n\n    CH_ANS  # bold replies? (yes for tty)\n    CH_CON  # connect timeout (5 secs)\n    CH_CUR  # filepointer to the current conversation (CH_DIR/.cur)\n    CH_DIR  # save chats here ($TMPDIR/chgpt)\n    CH_HES  # HTTP request headers to include in request (each must be newline terminated)\n    CH_KEY  # openai key (OPENAI_API_KEY)\n    CH_LOG  # error log name (CH_DIR/.err)\n    CH_MAX  # max tokens\n    CH_MOD  # model name (gpt-4o)\n    CH_RES  # response timeout (30 secs)\n    CH_ROB  # json object to include in request\n    CH_TEM  # chat temperature https://platform.openai.com/docs/api-reference/chat/create#chat-create-temperature\n    CH_TIT  # chat ID\n    CH_TOP  # top_p nucleus sampling https://platform.openai.com/docs/api-reference/chat/create#chat-create-top_p\n    CH_URL  # API URL (https://api.openai.com/v1/chat/completions)\n\nImagine, for example that we want to use a [stop](https://platform.openai.com/docs/api-reference/chat/create#chat-create-stop) sequence to terminate processing early. We can include that in the CH_ROB environment variable, which is a json object merged with the request object:\n\n    CH_ROB='{\"stop\":\"sugar\"}' ./ch n I am sweet and brown. Get me wet and I disappear. What am I?\n    The answer to this riddle is \n\n### Other APIs\n`ch` works with any compatible chat completion API that has a similar interface to OpenAI.\n\nAll you have to do is override the appropriate environment variables. These shell scripts do that:\n\n#### Anthropic\nAnthropic [requires](https://docs.anthropic.com/en/api/messages) different HTTP headers and returns a different response object compared to the other APIs.\n\n    #!/bin/sh\n    export CH_MAX=1024                                         # max tokens, required\n    export CH_DIR=\"/tmp/anthropic\"                             # save to alt dir\n    export CH_KEY=\"$ANTHPC_API_KEY\"                            # use the anthropic API key\n    export CH_HEA=\"x-api-key: $CH_KEY\"                         # override auth header\n    export CH_HES=\"anthropic-version: 2023-06-01\\n\"            # include version header\n    export CH_MOD=\"claude-3-5-sonnet-20241022\"                 # anthropic model name\n    export CH_URL=\"https://api.anthropic.com/v1/messages\"      # anthropic API URL\n    export CH_RJQ='.content | .[] | {\"role\":\"assistant\",\"content\":.text}' # parse the response\n    ch \"$@\"                                                    # ch must be in PATH\n#### DeepSeek\nDeepSeek [follows](https://api-docs.deepseek.com/api/create-chat-completion) the OpenAI API.\n\n    #!/bin/sh\n    export CH_DIR=\"/tmp/dpseek\"                                # save to alt dir\n    export CH_KEY=\"$DPSEEK_API_KEY\"                            # use the deepseek API key\n    export CH_MOD=\"deepseek-chat\"                              # deepseek model name\n    export CH_URL=\"https://api.deepseek.com/chat/completions\"  # deepseek API URL\n    ch \"$@\"                                                    # ch must be in PATH\n\n#### Perplexity\nPerplexity [follows](https://docs.perplexity.ai/api-reference/chat-completions) the OpenAI API.\n\n    #!/bin/sh\n    export CH_DIR=\"/tmp/ppxty\"                                 # save to alt dir\n    export CH_KEY=\"$PPLXTY_API_KEY\"                            # use the ppx API key\n    export CH_MOD=\"sonar\"                                      # ppx model name\n    export CH_URL=\"https://api.perplexity.ai/chat/completions\" # ppx API URL\n    ch \"$@\"                                                    # ch must be in PATH\n\n### MIT License\n\nCopyright (c) 2025 David Farrell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnmfarrell%2Fch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdnmfarrell%2Fch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnmfarrell%2Fch/lists"}