{"id":14867200,"url":"https://github.com/monochromegane/afa","last_synced_at":"2025-12-30T01:15:59.141Z","repository":{"id":257186791,"uuid":"857562030","full_name":"monochromegane/afa","owner":"monochromegane","description":"AFA is a terminal-friendly AI command.","archived":false,"fork":false,"pushed_at":"2024-09-18T07:44:34.000Z","size":1869,"stargazers_count":50,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-11T22:33:33.117Z","etag":null,"topics":["go"],"latest_commit_sha":null,"homepage":"","language":"Go","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/monochromegane.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2024-09-15T01:27:22.000Z","updated_at":"2024-12-28T02:10:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"59d79140-0bc2-481f-8d54-e06a527c11d4","html_url":"https://github.com/monochromegane/afa","commit_stats":null,"previous_names":["monochromegane/afa"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/monochromegane/afa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monochromegane%2Fafa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monochromegane%2Fafa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monochromegane%2Fafa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monochromegane%2Fafa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monochromegane","download_url":"https://codeload.github.com/monochromegane/afa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monochromegane%2Fafa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275868539,"owners_count":25542979,"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","status":"online","status_checked_at":"2025-09-19T02:00:09.700Z","response_time":108,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["go"],"created_at":"2024-09-20T04:01:01.659Z","updated_at":"2025-09-19T02:30:46.222Z","avatar_url":"https://github.com/monochromegane.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"AFA (AI for All)\n=======\n\n[![Actions Status](https://github.com/monochromegane/afa/workflows/tagpr/badge.svg?branch=main)][actions]\n\n[actions]: https://github.com/monochromegane/afa/actions?workflow=tagpr\n\n\n$$\\text{AI for All} := \\forall x \\in X \\, \\exists \\mathrm{AI}(x)$$\n\nAFA is a terminal-friendly AI command. It enables new behaviors through ad-hoc prompts without requiring programming implementation.\n\nAFA processes text streams as its input and output. Text is a flexible and universal interface, making it easy to interact across various environments and tools.\nAdditionally, it integrates with rich TUI tools to provide an interactive chat experience in the terminal.\n\nWith AFA, let's collaborate with both existing and unknown commands in line with the [UNIX philosophy](https://en.wikipedia.org/wiki/Unix_philosophy).\n\n- *Prompt* programs that do one thing and do it well.\n- *Prompt* programs to work together.\n- *Prompt* programs to handle text streams, because that is a universal interface.\n\n## Demo\n\n### Chat using a Rich TUI\n\n![Chat](examples/chat.gif)\n\n### Command Suggestions using ZLE\n\n![Command Suggestions](examples/command_suggestion.gif)\n\n### Code Suggestions using Vim\n\n![Code Suggestions](examples/code_suggestion.gif)\n\n## Features\n\n- Acts as a terminal-friendly AI command.\n- Acts as a chat client with a rich terminal user interface (TUI).\n- Supports contextual prompts for both system and user using templates.\n- Accepts prompts, standard input, and file paths as context.\n- Manages sessions, allowing for quick resumption via the `resume` sub-command.\n- Supports structured output with a safely escaped JSON option, facilitating easy integration with other commands.\n- The core application operates independently of third-party libraries.\n- Supports `OpenAI` as an AI model (support for other AI models is planned for the future).\n\n## Usage\n\nRun the interactive chat with:\n\n```sh\nafa new\n```\n\nUse a rich TUI viewer in chat mode with:\n\n```sh\nafa new -V\n```\n\nStart the interactive chat with additional information by executing:\n\n```sh\necho $ERROR_MESSAGE | afa new -p \"What is happening?\" /path/to/file1 /path/to/file2\n# Please be cautious; when standard input is provided, interactive mode is disabled.\n# Consider using process substitution.\n#=\u003e afa new -p \"What is happening?\" /path/to/file1 /path/to/file2 \u003c( echo $ERROR_MESSAGE )\n```\n\nContinue from the last session with:\n\n```sh\nafa resume\n```\n\nContinue from a specified session with:\n\n```sh\n# The command `afa list` displays past sessions.\nafa source -l SESSION_NAME\n```\n\nSpecify the user prompt with:\n\n```sh\n# `Message`, `MessageStdin`, and `Files` that include `File` with `Name` and `Content` members can be used in the template file.\necho \"Please explain the following.\\n{{ (index .Files 0).Content }}\" \u003e CONFIG_PATH/templates/user/explain.tmpl\nafa -u explain /path/to/file\n```\n\nRun script mode with:\n\n```sh\n# When no subcommand is specified, afa run as `afa new -script` which means `-I=false -H=false -S=false -V=false -L=false`\npbpaste | afa -p \"Transrate this\" | pbcopy\n```\n\nSpecify the schema for structured output with:\n\n```sh\ncat \u003c\u003c\u003c EOS \u003e CONFIG_PATH/schemas/command_suggestion.json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"suggested_command\": {\n      \"type\": \"string\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"required\": [\n    \"suggested_command\"\n  ]\n}\nEOS\n\nP=\"List Go files from the directory named 'internal' and print the first line of each file.\"\nafa new -script -j command_suggestion -p $P | jq -r '.suggested_command'\n#=\u003e find internal -name '*.go' -exec head -n 1 {} \\;\n```\n\n## Installation\n\nFollow these steps to install the tool and viewer:\n\n```console\n# Install the core application\ngo install github.com/monochromegane/afa@latest\n\n# Install the TUI viewer\ngo install github.com/monochromegane/afa-tui@latest\n```\n\nYou can download binaries from gihub releases.\n- AFA: [https://github.com/monochromegane/afa/releases](https://github.com/monochromegane/afa/releases)\n- AFA-TUI: [https://github.com/monochromegane/afa-tui/releases](https://github.com/monochromegane/afa-tui/releases)\n\nYou can also use [Homebrew](https://brew.sh/):\n\n```console\nbrew install monochromegane/tap/afa monochromegane/tap/afa-tui\n```\n\n## Configuration\n\nInitialize the setup:\n\n```console\nafa init\n```\n\n### Default Options\n\nThe configuration file named `afa/option.json` should be located at the path specified by Go's [os.UserConfigDir](https://pkg.go.dev/os#UserConfigDir).\n\n\u003e On Unix systems, it returns `$XDG_CONFIG_HOME` as specified by [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) if non-empty, else `$HOME/.config`. On Darwin, it returns `$HOME/Library/Application Support`. On Windows, it returns `%AppData%`. On Plan 9, it returns `$home/lib`.\n\n### API Keys\n\nThe configuration file named `CONFIG_PATH/afa/secrets.json`.\n\n### Tempates\n\nAFA supports the use of template files, which can be placed in the `templates/{system,user}` directories with the `.tmpl` extension.\nYou can specify the template to use by providing the name without the extension using `-s` (for system templates) or `-u` (for user templates) options.\n\nTemplates allow you to dynamically insert information. You can utilize the following placeholders within your templates:\n\n- `Message`: A string that can be replaced with a specific message by `-p` opition.\n- `MessageStdin`: This placeholder can take input from the standard input as a message.\n- `Files`: A collection of file objects, where each file has `Name` and `Content` members.\n\n### Schemas\n\nSimilar to templates, schema files can be placed in the `schemas` directory and should have a `.json` extension.\nYou can specify the schema to use by providing the name without the `.json` extension using the `-j` option.\n\n## Cache\n\n### Sessions\n\nThe session files named `afa/sessions/SESSION_NAME.json` should be located at the path specified by Go's [os.UserCacheDir](https://pkg.go.dev/os#UserCacheDir).\n\n\u003e On Unix systems, it returns `$XDG_CACHE_HOME` as specified by [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) if non-empty, else `$HOME/.cache`. On Darwin, it returns `$HOME/Library/Caches`. On Windows, it returns `%LocalAppData%`. On Plan 9, it returns `$home/lib/cache`.\n\n## Practical Examples\n\n### Command Suggestions using ZLE\n\nFirstly, we prepare a wrapper for suggestions named `afa_command_suggestion.zsh`, as shown below:\n\n```zsh\n#!/bin/zsh\n\nprompt_=\"\"\n\nwhile getopts p: OPT\ndo\n  case $OPT in\n    \"p\" ) prompt_=\"$OPTARG\";;\n    *) echo \"Error: Invalid option.\" \u003e\u00262; exit 1;;\n  esac\ndone\n\nshift `expr $OPTIND - 1`\n\nsuggested_command=$(afa new -script -j command_suggestion -u command_suggestion -p \"$prompt_\")\nif [ $? -ne 0 ]; then\n  echo \"Error: Failed to generate suggested command.\" \u003e\u00262\n  exit 1\nfi\n\ncommand_new=$(printf \"%s\" \"$suggested_command\" | jq -r '.suggested_command')\nif [ $? -ne 0 ]; then\n  echo \"Error: No suggested command received.\" \u003e\u00262\n  exit 1\nfi\n\necho \"$command_new\"\n```\n\nAnd we also prepare user prompt and schema files.\n\n`CONFIG_PATH/afa/templates/user/command_suggestion.json`\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"suggested_command\": {\n      \"type\": \"string\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"required\": [\n    \"suggested_command\"\n  ]\n}\n```\n\n`CONFIG_PATH/afa/schemas/command_suggestion.tmpl`\n\n~~~markdown\nYou are an assistant supporting operations in the terminal. Please suggest commands based on the following requirements.\n\n## Objective\n\n{{ .Message }}\n\n## Requirements\n\n- Commands executable in macOS's zsh.\n- Suggest command only, without explanations or comments.\n- The output should follow the provided json_schema.\n\n## json_schema\n\n```json\n{\n  \"suggested_command\": \"\u003cFinal suggested command\u003e\"\n}\n```\n~~~\n\nNext, we prepare a function for ZLE:\n\n```zsh\nfunction _afa-suggest-command() {\n  local command=$(afa_command_suggestion.zsh -p \"$BUFFER\")\n  if [ -n \"$command\" ]; then\n    BUFFER=\"$command\"\n  fi\n  CURSOR=$#BUFFER\n  zle reset-prompt\n}\n```\n\nFinally, we add a function setting and key bindings to the `.zshrc` as follows:\n\n```zsh\nautoload -Uz _afa-suggest-command\n\nzle -N afa-suggest-command _afa-suggest-command\nbindkey '^G^K' afa-suggest-command\n```\n\n### Code Suggestions using Vim\n\nFirst, we prepare a wrapper for suggestions named `afa_code_suggestion.zsh`, as shown below:\n\n```zsh\n#!/bin/zsh\n\nfile_path=\"\"\nfile_type=\"\"\nprompt_=\"\"\n\nwhile getopts f:e:p: OPT\ndo\n  case $OPT in\n    \"f\" ) file_path=\"$OPTARG\";;\n    \"e\" ) file_type=\"$OPTARG\";;\n    \"p\" ) prompt_=\"$OPTARG\";;\n    *) echo \"Error: Invalid option.\" \u003e\u00262; exit 1;;\n  esac\ndone\n\nshift `expr $OPTIND - 1`\n\ncode_org=$(cat)\nsuggested_code=$(echo \"$code_org\" | afa new -script -j code_suggestion -u code_suggestion -p \"$prompt_\" \u003c(echo \"$file_path\") \u003c(echo \"$file_type\") \"$@\")\nif [ $? -ne 0 ]; then\n  echo \"Error: Failed to generate suggested code.\" \u003e\u00262\n  echo \"$code_org\"\n  exit 1\nfi\n\ncode_new=$(printf \"%s\" \"$suggested_code\" | jq -r '.suggested_code')\nif [ $? -ne 0 ]; then\n  echo \"Error: No suggested code received.\" \u003e\u00262\n  echo \"$code_org\"\n  exit 1\nfi\n\necho \"$code_new\"\n```\n\nAnd we also prepare user prompt and schema files.\n\n`CONFIG_PATH/afa/templates/user/code_suggestion.json`\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"suggested_code\": {\n      \"type\": \"string\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"required\": [\n    \"suggested_code\"\n  ]\n}\n```\n\n`CONFIG_PATH/afa/schemas/code_suggestion.tmpl`\n\n~~~markdown\nYou are an assistant supporting coding tasks. Please suggest code modifications or generate new code based on the following requirements.\n\n{{- if .MessageStdin }}\n\n## Current Code\n\n- File: {{ (index .Files 0).Content -}}\n- Language: {{ (index .Files 1).Content -}}\n\n```\n{{ .MessageStdin }}```\n{{ end -}}\n\n{{- if ge (len .Files) 3 }}\n## Content of Related Files\n{{ range $i, $f := .Files }}\n{{- if ge $i 2 }}\n- File: {{ $f.Name }}\n```\n{{ $f.Content }}```\n{{ end -}}\n{{ end }}\n{{ end -}}\n\n## Objective\n\n{{ .Message }}\n\n## Requirements\n\n- Maintain the current structure of the existing functions and classes as much as possible.\n- Necessary libraries are already installed, so installation steps are not required.\n- Suggest code only, without explanations or comments.\n- The output should follow the provided json_schema.\n\n## json_schema\n\n```json\n{\n  \"suggested_code\": \"\u003cFinal suggested code\u003e\"\n}\n```\n~~~\n\nFinally, we add a command for Vim:\n\n```vimrc\nset splitright\ncommand DiffOrig vert new | set bt=nofile | r ++edit # | 0d_\n      \\ | diffthis | wincmd p | diffthis\n\ncommand -nargs=* -range=% -complete=file Afa \u003cline1\u003e,\u003cline2\u003ecall AfaFn(\u003cf-args\u003e)\nfunction AfaFn(...) range\n  let user_input = input(\"Enter prompt: \")\n  redraw\n  let cmd = a:firstline . ',' . a:lastline . '! afa_code_suggestion.zsh -f % -e %:e -p ' . shellescape(user_input) . ' ' . join(a:000, ' ')\n  execute cmd\nendfunction\n```\n\n### Error Message Explanations using TMUX Capture Panel Function\n\nWe prepare a Zsh function to capture the output of the last command:\n\n```zsh\nfunction _afa-capture() {\n    local start_line=-100\n    local last_command=$(fc -l -n -1)\n    local capture=$(tmux capture-pane -S \"$start_line\" -p)\n\n    if match=$(echo \"$capture\" | grep -F -n \"$last_command\"); then\n      local last_line_num=$(echo \"$match\" | tail -n 1 | cut -d\":\" -f1)\n      local result=$(echo \"$capture\" | awk -v start=\"$last_line_num\" 'NR \u003e= start')\n      echo $result | afa new -u explain\n    else\n      echo \"\\\"$last_command\\\" not found in the capture panel.\"\n    fi\n\n    zle reset-prompt\n}\n```\n\nHere is an example of a general `explain` user prompt template:\n\n~~~markdown\nPlease explain the following commands and their results, as well as the content of the provided files. Additionally, provide solutions if necessary.\n\n{{ .Message }}\n{{ if .MessageStdin }}\n```\n{{ .MessageStdin }}```\n{{- end }}\n{{ range .Files }}\n- File: {{ .Name }}\n```\n{{ .Content }}```\n{{ end -}}\n~~~\n\nAnd we add a function setting and key bindings to the `.zshrc` as follows:\n\n```zsh\nautoload -Uz _afa-capture\n\nzle -N afa-capture _afa-capture\nbindkey '^G^E' afa-capture\n```\n\n### GitHub Pull Request Content Suggestions using ZLE and gh Command\n\nFirstly, we prepare a wrapper for suggestions named `afa_github_pull_request.zsh`, as shown below:\n\n```zsh\n#!/bin/zsh\n\nprompt_=\"\"\n\nwhile getopts p: OPT\ndo\n  case $OPT in\n    \"p\" ) prompt_=\"$OPTARG\";;\n    *) echo \"Error: Invalid option.\" \u003e\u00262; exit 1;;\n  esac\ndone\n\nshift `expr $OPTIND - 1`\n\npull_request_template=\".github/pull_request_template.md\"\n\ncurrent_branch=$(git branch --show-current)\ngit fetch --quiet\nif ! git diff --quiet HEAD origin/\"$current_branch\"; then\n  echo \"You have unsynced changes. Please push to the remote.\" \u003e\u00262\n  exit 1\nfi\n\npull_request=$(afa new -script -u github_pull_request -j github_pull_request -p \"$prompt_\" \u003c( git diff --no-ext-diff origin ) \u003c( git log --format=\"- %s\" --no-merges origin..HEAD ))\nif [ $? -ne 0 ]; then\n  echo \"Error: Failed to generate suggested github pull request.\" \u003e\u00262\n  exit 1\nfi\n\ntitle=$(printf \"%s\" \"$pull_request\" | jq -r '.title_for_github_pull_request')\nif [ $? -ne 0 ]; then\n  echo \"Error: No suggested github pull request received.\" \u003e\u00262\n  exit 1\nfi\n\nbody=$(printf \"%s\" \"$pull_request\" | jq -r '.body_for_github_pull_request')\nif [ $? -ne 0 ]; then\n  echo \"Error: No suggested github pull request received.\" \u003e\u00262\n  exit 1\nfi\n\nif [[ -f \"$pull_request_template\" ]]; then\n  template_body=$(\u003c\"$pull_request_template\")\n  body_with_template=$(printf \"%s\\n\\n---\\n%s\" \"$body\" \"$template_body\")\nelse\n  body_with_template=$body\nfi\n\ngh pr create --web --title=\"$title\" --body=\"$body_with_template\"\n```\n\nAnd we also prepare user prompt and schema files.\n\n`CONFIG_PATH/afa/templates/user/github_pull_request.json`\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"title_for_github_pull_request\": {\n      \"type\": \"string\"\n    },\n    \"body_for_github_pull_request\": {\n      \"type\": \"string\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"required\": [\n    \"title_for_github_pull_request\",\n    \"body_for_github_pull_request\"\n  ]\n}\n```\n\n`CONFIG_PATH/afa/schemas/github_pull_request.tmpl`\n\n~~~markdown\nBased on the following information, please propose a title and body for a GitHub pull request.\n\n## Summary of Changes (from git diff information):\n\n{{ (index .Files 0).Content }}\n## Related Commit Messages (from git log information):\n\n{{ (index .Files 1).Content }}\n\n{{- if ne .Message \"\" }}\n## Background of Changes\n\n{{ .Message }}\n{{ end }}\n## Requirements:\n\n- Use Markdown format.\n- Focus on the purpose and background rather than the details of the changes.\n- Propose only the title and body without extra explanations or comments.\n- Start by \"# Automatically Generated Pull Request Description\".\n- And then:\n- \"## Summary\"\n- \"## Changes\", List multiple key changes. Provide a brief explanation for each key change.\n- Write Outlines only.\n~~~\n\nNext, we prepare a function for ZLE:\n\n```zsh\nfunction _afa-github-pull-request() {\n  afa_github_pull_request.zsh -p \"$BUFFER\"\n  BUFFER=\"\"\n  CURSOR=$#BUFFER\n  zle reset-prompt\n}\n```\n\nFinally, we add a function setting and key bindings to the `.zshrc` as follows:\n\n```zsh\nautoload -Uz _afa-github-pull-request\n\nzle -N afa-github-pull-request _afa-github-pull-request\nbindkey '^G^P' afa-github-pull-request\n```\n\n### Session Selection using peco\n\nWe prepare a function for ZLE:\n\n```zsh\nfunction _afa-source() {\n  local selected_session=$(afa list | peco --query \"$LBUFFER\")\n  if [ -n \"$selected_session\" ]; then\n    local session_name=$(echo \"$selected_session\" | cut -f1)\n    BUFFER=\"afa source -l ${session_name}\"\n    zle accept-line\n  fi\n  zle clear-screen\n}\n```\n\nWe add a function setting and key bindings to the `.zshrc` as follows:\n\n```zsh\nautoload -Uz _afa-source\n\nzle -N afa-source _afa-source\nbindkey '^G^S' afa-source\n```\n\n## License\n\n[MIT](https://github.com/monochromegane/afa/blob/master/LICENSE)\n\n## Author\n\n[monochromegane](https://github.com/monochromegane)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonochromegane%2Fafa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonochromegane%2Fafa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonochromegane%2Fafa/lists"}