{"id":44825517,"url":"https://github.com/avivsinai/yoetz","last_synced_at":"2026-05-15T23:15:35.806Z","repository":{"id":337004459,"uuid":"1148806034","full_name":"avivsinai/yoetz","owner":"avivsinai","description":"Fast CLI-first LLM council + bundler + multimodal gateway","archived":false,"fork":false,"pushed_at":"2026-04-11T12:28:08.000Z","size":802,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T14:14:03.811Z","etag":null,"topics":["ai","cli","code-review","coding-agents","llm","llm-gateway","multimodal","rust"],"latest_commit_sha":null,"homepage":"https://github.com/avivsinai/yoetz","language":"Rust","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/avivsinai.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-03T11:43:34.000Z","updated_at":"2026-04-11T12:20:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/avivsinai/yoetz","commit_stats":null,"previous_names":["avivsinai/yoetz"],"tags_count":52,"template":false,"template_full_name":null,"purl":"pkg:github/avivsinai/yoetz","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avivsinai%2Fyoetz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avivsinai%2Fyoetz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avivsinai%2Fyoetz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avivsinai%2Fyoetz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/avivsinai","download_url":"https://codeload.github.com/avivsinai/yoetz/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avivsinai%2Fyoetz/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31774550,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T20:17:16.280Z","status":"ssl_error","status_checked_at":"2026-04-13T20:17:08.216Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["ai","cli","code-review","coding-agents","llm","llm-gateway","multimodal","rust"],"created_at":"2026-02-16T21:36:36.715Z","updated_at":"2026-05-15T23:15:35.780Z","avatar_url":"https://github.com/avivsinai.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yoetz\n\n\u003cp\u003e\n  \u003cimg src=\"assets/branding/yoetz-quorum-mark.svg\" alt=\"Yoetz quorum mark\" width=\"96\" height=\"96\"\u003e\n\u003c/p\u003e\n\n[![CI](https://github.com/avivsinai/yoetz/actions/workflows/ci.yml/badge.svg)](https://github.com/avivsinai/yoetz/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Rust: 1.88+](https://img.shields.io/badge/rust-1.88%2B-orange.svg)](https://www.rust-lang.org/)\n\nFast, CLI-first LLM council + bundler + multimodal gateway for coding agents.\n\n\u003e **Note**: This project is under active development. APIs may change.\n\n## Why yoetz?\n\nMost LLM CLI tools focus on a single provider or a single workflow. yoetz is different:\n\n- **Multi-model council** — get consensus from multiple LLMs in one command, not sequential copy-paste between tabs\n- **Multimodal native** — text, images, and video as first-class inputs across providers\n- **Agent-first design** — structured JSON output, local budget tracking for ask/council/review, and agent skill integration out of the box\n- **Zero lock-in** — one config, any provider (OpenRouter, OpenAI, Gemini, LiteLLM), switch with a flag\n- **Bundle-aware** — package your codebase with gitignore-awareness for maximum LLM context\n\n## Table of Contents\n\n- [Why yoetz?](#why-yoetz)\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Architecture](#architecture)\n- [Supported Providers](#supported-providers)\n- [Environment Variables](#environment-variables)\n- [MSRV Policy](#msrv-policy)\n- [Contributing](#contributing)\n- [Verifying Downloads](#verifying-downloads)\n- [License](#license)\n\n## Features\n\n- **Bundle**: Package code files with gitignore-awareness for LLM context\n- **Ask**: Query LLMs with text, images, or video\n- **Council**: Multi-model consensus with configurable voting\n- **Review**: AI-powered code review for diffs and files\n- **Generate**: Create images (OpenAI) and videos (Sora, Veo)\n- **Browser**: Fallback to web UIs via recipes\n\n## Installation\n\n### Homebrew (macOS / Linux)\n\n```bash\nbrew install avivsinai/tap/yoetz\n```\n\n### Scoop (Windows)\n\n```powershell\nscoop bucket add avivsinai https://github.com/avivsinai/scoop-bucket\nscoop install yoetz\n```\n\n### Pre-built Binaries\n\nDownload the latest release from [GitHub Releases](https://github.com/avivsinai/yoetz/releases).\n\n```bash\n# macOS (Apple Silicon)\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/yoetz-aarch64-apple-darwin.tar.gz\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/SHA256SUMS.txt\nshasum -a 256 -c SHA256SUMS.txt --ignore-missing\ntar xzf yoetz-aarch64-apple-darwin.tar.gz\nsudo mv yoetz /usr/local/bin/\n\n# macOS (Intel)\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/yoetz-x86_64-apple-darwin.tar.gz\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/SHA256SUMS.txt\nshasum -a 256 -c SHA256SUMS.txt --ignore-missing\ntar xzf yoetz-x86_64-apple-darwin.tar.gz\nsudo mv yoetz /usr/local/bin/\n\n# Linux (x86_64)\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/yoetz-x86_64-unknown-linux-gnu.tar.gz\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/SHA256SUMS.txt\nsha256sum -c SHA256SUMS.txt --ignore-missing\ntar xzf yoetz-x86_64-unknown-linux-gnu.tar.gz\nsudo mv yoetz /usr/local/bin/\n\n# Linux (ARM64)\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/yoetz-aarch64-unknown-linux-gnu.tar.gz\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/SHA256SUMS.txt\nsha256sum -c SHA256SUMS.txt --ignore-missing\ntar xzf yoetz-aarch64-unknown-linux-gnu.tar.gz\nsudo mv yoetz /usr/local/bin/\n```\n\n### From Source\n\n```bash\ncargo install --git https://github.com/avivsinai/yoetz --locked\n```\n\n### Build Locally\n\n```bash\ngit clone https://github.com/avivsinai/yoetz.git\ncd yoetz\ncargo build --release\n```\n\n### Agent Skill (Claude Code / Codex CLI)\n\n```bash\n# Via skills marketplace\n/plugin marketplace add avivsinai/skills-marketplace\n/plugin install yoetz@avivsinai-marketplace\n\n# Via skills.sh\nnpx skills add avivsinai/yoetz\n\n# Via skild.sh\nnpx skild install @avivsinai/yoetz\n```\n\n## Quick Start\n\n### Configuration\n\nCreate `~/.config/yoetz/config.toml`:\n\n```bash\nmkdir -p ~/.config/yoetz\ncp docs/config.example.toml ~/.config/yoetz/config.toml\n```\n\nYoetz also loads the legacy `~/.yoetz/config.toml`, profiles under those config\ndirectories, repo-local `./yoetz.toml` with untrusted-provider safeguards, and\n`YOETZ_CONFIG_PATH` when set.\n\n### Basic Usage\n\n```bash\n# Bundle files for LLM context\nyoetz bundle --prompt \"Review this code\" --files \"src/**/*.rs\"\n```\n\nBundles are trust boundaries: treat bundled repository content, issues, logs,\nand pasted browser output as untrusted prompt input. Keep instructions in\n`--prompt`, avoid bundling secrets, and review generated changes before applying\nthem.\n\n```bash\n# Ask a question\nyoetz ask --prompt \"Explain this function\" --files \"src/main.rs\"\n\n# Ask with structured JSON output (OpenAI-compatible)\nyoetz ask --prompt \"Return JSON only\" --provider openai --model gpt-5.2 --response-format json\n\n# Ask with an image (vision)\nyoetz ask --prompt \"Describe this diagram\" --image diagram.png --provider gemini --model gemini-3-flash-preview\n\n# Override MIME type for signed/extensionless URLs\nyoetz ask --prompt \"Describe this\" --image https://example.com/signed --image-mime image/png\n\n# Ask about a video\nyoetz ask --prompt \"Summarize this\" --video meeting.mp4 --provider gemini --model gemini-3-flash-preview\n\n# Override video MIME type for signed/extensionless URLs\nyoetz ask --prompt \"Summarize this\" --video https://example.com/signed --video-mime video/mp4\n```\n\n\u003e Note: Gemini can return empty content if `--max-output-tokens` is too low because tokens are consumed by thoughts. If you see warnings or empty output, increase the limit.\n\n```bash\n# Debug raw provider responses\nyoetz --debug ask --provider gemini --model gemini-3-flash-preview --prompt \"ping\"\n\n# Resolve live model IDs before putting them in scripts\nyoetz models frontier --format json\n\n# Multi-model council\nyoetz council --prompt \"Review this PR\" --models \"openai/\u003cmodel-id\u003e,openrouter/anthropic/claude-sonnet-4.5\"\n\n# Code review\nyoetz review diff --model openai/gpt-5.2-codex\nyoetz review file --path src/lib.rs --provider openrouter --model anthropic/claude-sonnet-4.5\n```\n\nCouncil calls require explicit model IDs and cost roughly scales with every\nselected model. Budget flags are local preflight/accounting aids for\nask/council/review, not provider-side hard limits; verify current model IDs and\nprovider capabilities before relying on examples.\n\n### Generation\n\n```bash\n# Generate images\nyoetz generate image --prompt \"A cozy cabin in snow\" --provider openai --model gpt-image-1.5\n\n# Generate video (Sora)\nyoetz generate video --prompt \"Drone flyover\" --provider openai --model sora-2-pro\n\n# Generate video (Veo)\nyoetz generate video --prompt \"Ocean waves\" --provider gemini --model veo-3.1-generate-preview\n```\n\n### Browser Fallback\n\n```bash\n# Direct browser command\nyoetz browser exec -- open https://chatgpt.com/\n\n# Use a recipe\nyoetz browser recipe --recipe recipes/chatgpt.yaml --bundle bundle.md\n\n# JSON output aggregates steps\nyoetz --format json browser recipe --recipe recipes/chatgpt.yaml --bundle bundle.md\n```\n\nThe default browser stack remains extension-free: ChatGPT recipes use\n`chrome-devtools-mcp`, then `dev-browser`, then `agent-browser` / cookie\nfallbacks as needed. The experimental `chrome-extension-native` transport is an\nexplicit opt-in exception for ChatGPT Pro runs that need install-once native\nmessaging instead of CDP approval prompts. This native-host path is currently\nmacOS/Linux-only; Windows CLI artifacts still ship, but Windows native-host\nregistration is not implemented yet.\n\n```bash\nyoetz browser extension setup --chatgpt --open-chrome\nyoetz browser extension install-host --chatgpt\nyoetz browser extension doctor --chatgpt\nyoetz browser extension status --chatgpt\nyoetz browser extension reconnect --chatgpt\nyoetz browser extension reload --chatgpt\nyoetz browser extension canary --chatgpt\nyoetz browser extension inspect --chatgpt --run-id \u003crun-id\u003e\nyoetz browser extension grant-identity --chatgpt\nyoetz browser check --transport chrome-extension-native\n\nyoetz browser recipe --recipe chatgpt --transport chrome-extension-native --bundle bundle.md\nyoetz browser recipe --recipe chatgpt --transport chrome-extension-native --bundle bundle.md --var profile_email=user@example.com\nyoetz browser recipe --recipe chatgpt --transport chrome-extension-native --bundle bundle.md --var extension_instance_id=ext_...\n```\n\nFor the extension transport, every loaded Chrome profile publishes a separate\nnative bridge instance. With exactly one connected instance, Yoetz uses it. With\nmultiple connected instances, pass `--var profile_email=\u003cemail\u003e` or\n`--var extension_instance_id=\u003cid\u003e` from `status --chatgpt` so Yoetz can route to\nthe matching Chrome profile; otherwise it fails closed rather than guessing. If\nChrome does not expose the profile email to the extension, an explicit\n`profile_email` request also fails closed, but the stable\n`extension_instance_id` selector still works. These selectors identify the\nChrome extension/profile instance, not the ChatGPT account or Enterprise\nworkspace. To use `profile_email`, first opt in with\n`yoetz browser extension grant-identity --chatgpt`; exact\n`browser_context_id` targeting remains CDP-only.\n\nRelease builds publish the ChatGPT native extension as a separate versioned zip\nartifact alongside the CLI archives. To install or update it manually, unzip the\nartifact, open `chrome://extensions`, enable Developer mode, choose **Load\nunpacked**, and select the extracted zip directory itself. From a source\ncheckout, select `extensions/chatgpt-native` instead. When updating an unpacked\ninstall, replace the extracted files and click the extension row's reload\nbutton, or run `yoetz browser extension reload --chatgpt` when the currently\nloaded extension already supports the reload command; then run\n`yoetz browser extension reconnect --chatgpt` and\n`yoetz browser extension doctor --chatgpt`.\n\nFor agent-driven setup, `yoetz browser extension setup --chatgpt --open-chrome`\ndoes everything Chrome allows from the CLI: it installs or updates the native\nhost, finds the unpacked extension directory when available, opens\n`chrome://extensions`, and prints the exact folder to select. Chrome still\nrequires the explicit **Load unpacked** UI step for local unpacked extensions.\nIf the extension directory is not discoverable from the current checkout or\ninstallation, set `YOETZ_CHATGPT_NATIVE_EXTENSION_DIR` to the extracted\nextension directory and rerun `setup`.\n\nFor normal Google Chrome profiles, `install-host` writes the Native Messaging\nhost manifest to Chrome's default user path. If Chrome is launched with a custom\n`--user-data-dir`, or if you are using Chrome for Testing or Chromium, set\n`YOETZ_CHROME_NATIVE_MESSAGING_DIR` to that browser user-data directory's\n`NativeMessagingHosts` folder before running `install-host`. On Windows this\ntransport fails closed until registry-based native-host setup is added.\nUse `yoetz browser check --transport chrome-extension-native` to verify the\ninstalled extension bridge without exercising CDP or triggering Chrome's remote\ndebugging approval dialog. Use `yoetz browser extension canary --chatgpt --live`\nonly when you intentionally want to submit a tiny live ChatGPT probe.\n\n### DX: ChatGPT Pro autonomous review via the extension transport\n\nThe transport drives upload → send → wait → extract reliably, but ChatGPT\nPro's file analyzer can still stall or return truncated answers on large\nreal-review attachments. This is not a stable token ceiling: in live testing,\nlarge review bundles around 60k and 220k effective tokens failed, while tiny\nsentinel canaries succeeded. For autonomous code review, prefer focused\nper-directory slices over a single large bundle, and raise `wait_timeout_ms`\nfor jobs that are expected to spend a long time in ChatGPT file analysis.\nYoetz fails terminally with privacy-scoped diagnostics (`response_timeout`,\nextraction method/status, assistant-turn counts, and bounded scoped snippets)\nrather than returning partial or thought-only chrome as success.\n\nReal ChatGPT Pro review jobs can run for 15-20 minutes while file analysis\nruns. That is expected. The native-extension transport emits low-noise lifecycle\nand `waiting_response` progress to stderr, including in `--format json` mode so\nstdout stays parseable. The recipe response poll default is 30 minutes; agents\nshould keep the original process attached, write the response with\n`--output-final`, and avoid launching a duplicate run just because progress is\nsparse. Use `--var wait_timeout_ms=2400000` only for slices that are expected to\nexceed the default. If a terminal upload/send/wait error is reported, inspect\nthe marked tab with\n`yoetz browser extension inspect --chatgpt --run-id \u003crun-id\u003e` before deciding\nwhether an intentional rerun is safe.\n\nThe recipe never auto-falls-back to another transport once a side effect has\nlanded in the user's tab. If the run fails after upload/send, the error\nincludes a manual recovery hint (`window.name` marker, `_yoetz` URL marker,\nextension marker prefix) so an agent can decide whether to reuse the tab or\nabort. Pass `--allow-cdp-fallback` only if you understand that explicitly\npermits a second submission via CDP.\n\nThe default ChatGPT target is Pro with Extended enabled. `model=auto` prefers\nthe Pro/Extended personal UI control when it exists, and the enterprise model\nswitcher remains supported. The `--var extended=false` toggle is best-effort\nand only runs when explicitly requested. Yoetz scopes the chip match to the\nChatGPT composer with negative-control guards, but ChatGPT re-skins the\nExtended thinking control occasionally; on a miss the run continues with\nwhatever Extended state the tab was in and emits a warning.\n\nIf the next ChatGPT run after an unexplained failure should inspect the\nYoetz-owned tab without resubmitting, use\n`yoetz browser extension inspect --chatgpt --run-id \u003cid\u003e` to read the live\nextraction, conversation id, and privacy-scoped diagnostics through the\nextension bridge. Inspection is read-only, omits broad page text by default,\nand never restarts the run.\n\nIf inspection shows `response_extraction_failed` and the owned tab also contains\nonly a tiny/truncated assistant fragment, treat it as a bad ChatGPT answer and\nrerun intentionally with a smaller bundle or a more explicit prompt. If the tab\nvisibly contains the full answer, preserve the tab and report the extraction\nmiss instead of rerunning blindly.\n\n## Architecture\n\nSee [ARCHITECTURE.md](ARCHITECTURE.md) for design details.\n\n```\nyoetz/\n├── crates/\n│   ├── yoetz-core/       # Core library\n│   │   ├── bundle.rs     # File bundling with gitignore\n│   │   ├── config.rs     # TOML config loading + profiles\n│   │   ├── media.rs      # Media types for multimodal\n│   │   ├── output.rs     # JSON/JSONL formatting\n│   │   ├── paths.rs      # Home/XDG path helpers\n│   │   ├── registry.rs   # Model registry types\n│   │   ├── session.rs    # Session storage\n│   │   └── types.rs      # Shared types\n│   └── yoetz-cli/        # CLI binary\n│       ├── main.rs       # Command handlers\n│       ├── commands/     # ask, bundle, council, generate, models, pricing, review\n│       ├── providers/    # Provider-specific helpers not covered by litellm-rust\n│       ├── browser.rs    # Browser recipe orchestration\n│       ├── browser_extension_native.rs\n│       ├── chatgpt_recipe.rs\n│       ├── chatgpt_web.rs\n│       ├── chrome_devtools_mcp/\n│       ├── dev_browser.rs\n│       ├── live_attach.rs\n│       ├── live_cdp_daemon.rs\n│       ├── registry.rs   # Runtime model registry\n│       └── budget.rs     # Daily spend tracking\n├── recipes/              # Browser automation YAML\n└── docs/                 # Config examples and design decisions\n```\n\n## Supported Providers\n\n| Provider | Text | Vision | Image Gen | Video Gen | Video Understanding |\n|----------|------|--------|-----------|-----------|---------------------|\n| OpenRouter | Yes | via model | - | - | - |\n| OpenAI | Yes | Yes | Yes | Yes (Sora) | - |\n| Gemini | Yes | Yes | - | Yes (Veo) | Yes |\n| LiteLLM | Yes | via model | - | - | - |\n\n## Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `OPENROUTER_API_KEY` | OpenRouter API key |\n| `OPENAI_API_KEY` | OpenAI API key |\n| `GEMINI_API_KEY` | Google Gemini API key |\n| `ANTHROPIC_API_KEY` | Anthropic API key for direct Anthropic provider configs |\n| `XAI_API_KEY` | xAI API key for direct xAI/OpenAI-compatible provider configs |\n| `LITELLM_API_KEY` | LiteLLM proxy key |\n| `YOETZ_CONFIG_PATH` | Custom config path |\n| `YOETZ_AGENT=1` | Default command output to JSON for agent parsing |\n| `YOETZ_BROWSER_CDP` | CDP endpoint for browser attach/check/recipe commands |\n| `YOETZ_BROWSER_PROFILE` | Browser profile name used by browser flows |\n| `YOETZ_BROWSER_TARGET_PATH` | Browser target metadata path for live attach |\n| `YOETZ_AGENT_BROWSER_BIN` | Override `agent-browser` executable |\n| `YOETZ_DEV_BROWSER_BIN` | Override `dev-browser` executable |\n| `YOETZ_CHROME_NATIVE_MESSAGING_DIR` | Native Messaging host directory for custom Chrome/Chromium profiles |\n| `YOETZ_REGISTRY_PATH` | Override local model registry cache path |\n| `YOETZ_BUDGET_PATH` | Override local budget ledger path |\n\n## MSRV Policy\n\nThe minimum supported Rust version is **1.88**. MSRV is tested in CI and bumped only with minor releases.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.\n\n## Verifying Downloads\n\nVerify archive checksums before extracting or moving binaries into `PATH`:\n\n```bash\n# Download the archive and checksums file\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/yoetz-aarch64-apple-darwin.tar.gz\ncurl -fLO https://github.com/avivsinai/yoetz/releases/latest/download/SHA256SUMS.txt\n\n# Verify the downloaded archive (macOS)\nshasum -a 256 -c SHA256SUMS.txt --ignore-missing\n\n# Verify the downloaded archive (Linux)\nsha256sum -c SHA256SUMS.txt --ignore-missing\n\n# Then extract and install\ntar xzf yoetz-aarch64-apple-darwin.tar.gz\nsudo mv yoetz /usr/local/bin/\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favivsinai%2Fyoetz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Favivsinai%2Fyoetz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favivsinai%2Fyoetz/lists"}