diff --git a/CHANGELOG.md b/CHANGELOG.md index 4daa532..511a571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,188 @@ # Changelog +## Unreleased — mail, a real password vault, CAPTCHA hand-off, Claude Code parity + +1. **Mail.** `qodex mail add` connects any IMAP/SMTP mailbox (presets for Gmail, Outlook, Yahoo, + iCloud, Yandex, Zoho, Fastmail, AOL, GMX, Proton Bridge; app passwords explained). Tools + `mail_list`, `mail_read` (fenced as untrusted data), `mail_draft`, `mail_send` (always asks), + `mail_mark`, `mail_move`, `mail_download_attachment`. **Standing reply grants** that only you + can create (`/allow mail-replies`, Telegram `/allow`, or "always allow replies like this") let + same-thread replies to the original sender go out without a prompt — audited, capped per day, + revocable. **Watcher** (IMAP IDLE): new mail is announced; **rules** start a task on matching + mail with the email as data. Guide: [docs/MAIL.md](docs/MAIL.md). +2. **Password vault (Muse-style).** The vault key can live in the macOS Keychain / Secret Service / + Windows DPAPI (`qodex vault key migrate`); `qodex vault edit|rotate|import` (Chrome, Firefox, + Bitwarden, 1Password exports); `browser_login` signs in in one step (username-first forms, 2FA); + `vault_generate_and_fill` makes and saves a strong password on sign-up; `vault_request_login` + has *you* type a login into a masked prompt or the control center's secure form (sealed over + tunnels) — the agent never sees it; logins you type during a takeover are offered for saving; + a vault panel in the control center. Guide: [docs/VAULT_AND_CAPTCHA.md](docs/VAULT_AND_CAPTCHA.md). +3. **CAPTCHAs: a smart hand-off, never solving.** Bot checks are detected; self-clearing ones are + waited out; the rest are handed to you (Telegram card with a cropped screenshot and a one-tap, + short-lived live-view link; phone hand-off mode that relays your own press-and-hold / drag; + TUI hint) and QodeX continues by itself when the check is gone. The agent can never click, + type into, drag or analyze a challenge (`[CHALLENGE_HUMAN_ONLY]`). **`browser.stealth` is now + off by default** — no fingerprint spoofing. Visible browser in the TUI by default + (`browser.headless: auto`), per-site pacing. +4. **Claude Code parity.** **Mods** — JS/TS modules that hook QodeX itself (tool calls, prompts, + permission checks within the safety rules, commands, tools, UI above/under the prompt, timers), + compatible with Claude Code mods; `/mod new` has QodeX write one; built-ins `context-bar` + (`/context-bar`) and `you-should-know` ([docs/MODS.md](docs/MODS.md)). **Wrap-up allowance** + when a budget runs out mid-task (`--strict-budget` to disable). **Send now** (Ctrl+Enter / + Ctrl+X Ctrl+S) keeps a running shell command as a background job. **Auto-mode asks time out** + after `approval.unattendedTimeoutSec` (default 120 s) with a rewrite hint — never the critical + ones. **Project instructions** `first|all` (`/instructions`, GEMINI.md). **Models:** + `claude-opus-5-5` (new default), `claude-sonnet-5-5`, `claude-fable-5-1`; `/model opus|sonnet| + haiku|fable`. **`/checkup prompt-audit`** writes `PROMPT_AUDIT.md` + `prompt-audit.patch` + (nothing applied). Built-in skills **build-eval** and **hillclimb**. +5. **Lean browser mode** (`browser.lean`, default `auto` = headless only): images, fonts and + audio/video are skipped while nobody needs the pixels; DOM, scripts, forms, cookies and the + HTTP cache are untouched (per-tab CDP interception of those resource types only, not + `context.route`, which turns the cache off). Never on your own Chrome or localhost / LAN + pages; off for the rest of the session on a screenshot, takeover, live view or bot check. + 12-photo page: ~0 MB vs 5 MB downloaded, ~270 ms vs ~720 ms, ~100–180 MB less memory. +6. **Web Bot Auth — an honest agent identity** (`browser.botAuth`, off by default). QodeX + can sign its own requests with an Ed25519 key (HTTP Message Signatures / RFC 9421, tag + `web-bot-auth`) so a site recognises the agent and may let it through — the opposite of + detection evasion. `qodex browser bot-auth --init|--directory`; the private key lives in + `~/.qodex/browser/bot-auth/` (0600) and Sentinel keeps the agent out of it. Signs only + same-site document/xhr/fetch on public hosts; never loopback/LAN or the user's own + Chrome. No fingerprint spoofing, no hiding `navigator.webdriver`, no synthetic input. +7. **Fixes found while merging:** workflow recording dropped a human's Back on fast machines + (echo matching); the mail watcher missed mail that arrived between a check and the IDLE wait, + and `stop()` could wait out the IDLE timeout; Telegram `/unpair` confirmed before dropping the + approval channel; challenge detection stringified the page-title promise; the terminal's + secure login prompt could put keys typed right after Enter into the previous field (a false + "passwords do not match"), and now also takes a pasted password ending in Enter; the Wayland + backend measured the screen through a predictable file in the shared temp dir; `/mod new` + had a second, unreachable implementation. + +## Unreleased — standing goals, emergency stop, /learn, monitors + +1. **`/goal` — keep working until it is proven done.** `/goal + [--check ""] [--max N]` starts the task and, after each run, checks the goal: the check + command must exit 0, or (without one) the answer must cite evidence on a `GOAL_MET:` line. + Not met → another round with the check's output, up to `--max` (default 8, cap 50), then it + stops and says what is missing. `/goal` shows it, `/goal clear` drops it. +2. **Emergency stop.** `/stop` halts the running task, side runs, background jobs and dev + servers and clears the goal — mid-task too; `/stop all` also cancels every active mission. + Also in the control center (⏹ Stop) and Telegram (`/stop`, `/stop all`). +3. **`/learn [name]`.** Turns the task you just finished into an active skill with the + deterministic distiller (no model call); never overwrites a skill you wrote. +4. **Monitors.** `qodex schedule add --continuity` gives each run the previous answer so it + reports what changed; `--notify-on-change` skips the notification / delivery when nothing did. + `qodex schedule list` shows both. +5. **Protected instruction files.** Writes to `AGENTS.md`, `QODEX.md`, `CLAUDE.md`, `GEMINI.md`, + `AI.md`, `.cursorrules`, `.windsurfrules`, `.github/copilot-instructions.md`, the project's + `.qodex/` and `.cursor/rules/`, and `~/.qodex/skills|rules|hooks|memory` ask in every mode, + auto included — by edit tool or any shell command that writes, moves, deletes or chmods them. + No allow rule, tool-wide allow or "always yes" covers them. + +## Unreleased — a real auto mode + +**Auto mode now means "work without asking me" — except for money, passwords, messages and +damage outside the project.** The approval modes are `manual` (default), `edits` (the old +"auto": file edits run, shell asks) and `auto` (replaces "always yes"). Shift+Tab cycles them. + +1. **What auto mode asks.** Purchases, payments, passwords / credentials, sending messages and + QodeX's own safety settings (Sentinel-critical — a human answers in every mode), and + destructive actions outside the project: deleting or overwriting paths outside the workspace + roots, force-push and remote branch deletes, deleting remote data (cloud, Kubernetes, + `terraform destroy`, databases on other hosts, package unpublish), publishing (`npm publish`, + `docker push`, production deploys), system-level commands (`sudo`, `shutdown`, disks), and on + the web deleting data or changing an account on a non-local site. With nobody at the + terminal these go to the control center / Telegram / the mission queue, or are refused — + never auto-answered. +2. **What it doesn't.** Everything inside the project: edits, shell, installs, commits, rebases, + ordinary pushes, deleting project files, browser and desktop work Sentinel rates + non-critical. The agent's own questions are not asked either: the new `ask_user` tool and + plan approval (`present_plan`) answer "decide yourself" in auto mode, so the model picks a + sensible default, keeps going and lists its assumptions at the end; a plan presented in plan + mode is approved and carried out in the same turn. The system prompt gets a short + "Autonomous mode" section, and when the mode changes mid-task the running agent is told. + Sub-agents, side runs and missions started from an auto session follow the same policy. +3. **Turning it on.** Shift+Tab; `/auto on` (`/auto manual|edits|auto`, alias `/mode`); + `qodex --auto` or `qodex --approval-mode ` for the TUI and `-p` runs + (`-y`/`--yes` on a `-p` run now means auto mode); `qodex mission start … --auto`; or + `approval.defaultMode: auto` in `~/.qodex/config.yaml` — only the user config counts, a + project's `.qodex/config.yaml` cannot switch you into auto. `approval.extraRoots` lists more + folders auto mode treats as the project (cwd and the temp dir always count). +4. **TUI.** The status bar shows the mode as a badge (`manual` · `✎ accept edits` · + `⏵⏵ auto`); `/status` prints it. The first time auto is on, a one-line banner says what + still asks. Switching into auto with a prompt on screen answers it only when it is an + ordinary permission the auto policy allows — never a Sentinel prompt, never one the policy + still asks about, never with a standing "always". A Sentinel "always" answer keeps its + category-on-this-site scope instead of switching the whole session. +5. **Still in force.** `security.denyRules`, the hard-deny patterns and every budget + (`--budget-usd`, per-task caps) apply in auto mode exactly as before. + +## v3.0.0 — 2026-10-03 + +**QodeX gets its own computer: a dedicated browser, desktop control on every OS, background +missions, and a Sentinel that never lets it buy, pay, send or type a password without you.** + +QodeX is now a general autonomous agent in the spirit of Meta Muse and xAI Grok Bot — but it +runs on your machine, with your model, and also controls your desktop. Guide: +[docs/AGENT_PLATFORM.md](docs/AGENT_PLATFORM.md). + +1. **Dedicated QodeX Browser.** Persistent Chromium profiles (logins survive restarts), multi-tab + with popup tracking, accessibility snapshots with element refs, actions by ref that return a + fresh compact snapshot, set-of-marks screenshots, markdown/table extraction, downloads, + uploads, dialogs, PDF, network log, CDP attach to your own Chrome, stealth, and + `browser_agent` (an autonomous browser sub-agent). 28 `browser_*` tools; `qodex browser + open|status|profiles|reset-profile|close`. Chromium is discovered automatically even when + the installed Playwright expects another revision. `browser_evaluate` now returns values + (it always returned `undefined`). +2. **Desktop control on macOS, Linux (X11 + Wayland) and Windows.** Screenshot (HiDPI-aware, + downscaled with coordinate mapping), click/drag/move/scroll, Unicode typing (Persian via + paste), key combos, clipboard, open apps/files/URLs, list/focus windows, + `computer_use_locate` (vision grounding) and `computer_use_agent`. 15 `computer_use_*` tools. +3. **Missions.** `qodex mission start ""` / `mission_start` plans the goal into steps, runs + each on a fresh agent in a detached, resumable worker (keeps going after you close QodeX), + reports milestones, retries failures, writes a final report, and starts its own private + live view. `attach`, `status`, `approve|deny`, `steer`, `cancel`, `resume`; routines via + `qodex schedule add --mission`. Approvals work across processes. +4. **Sentinel.** One guard at the tool-execution choke point (main agent, sub-agents, missions, + MCP server). Purchases, payments, sending and credentials always need an explicit human + answer — `/auto on` and `--yes` cannot approve them; with nobody reachable they are refused. + English + Persian action classification, payment-gateway and secret detection (Luhn, Sheba, + IBAN, API keys), domain allow/block lists, protected QodeX files, JSONL audit log. Web and + window text is fenced as untrusted data and scanned for prompt injection (EN + FA, hidden + Unicode). +5. **Credential vault.** `qodex vault add` — AES-256-GCM, separate 0600 key, TOTP (RFC 6238). + `browser_fill_secret` fills only on the entry's own https origin, re-checks right before + typing, and never returns the value to the model. +6. **Control center.** `qodex control [--lan|--tunnel]` or `/control`: a token-protected web page + with the live browser view, human takeover, one-tap approvals, an activity timeline, + steering and missions (English + Persian). +7. **Workflows.** Record the agent's or your own demonstration (`qodex workflow record`, + `workflow_record`), replay with self-healing selectors, Sentinel checks and vault secrets at + zero model tokens per step; each workflow is also saved as a skill. +8. **Telegram channel.** `qodex telegram setup|pair|start`: approve actions with inline buttons, + start and follow missions, get screenshots and notifications — paired private chats only. +9. **Approvals everywhere.** A new ApprovalBroker routes every human decision to the terminal, + the control center and Telegram; the first answer wins. Terminal prompts are queued (no more + concurrent prompts clobbering each other) and Esc cancels a stuck one. +10. **Agent core.** Sub-agents work again (they failed on a database foreign key), run on fresh + agent instances, honor their iteration cap and inherit approvals; new `browser` and + `computer` operator roles; per-tool timeouts; loop guards that understand changing page + state; the completion gate accepts real-world actions as evidence; `web` and `desktop` task + profiles; tool relevance understands URLs and Persian site commands; headless no longer + auto-accepts edits without `--yes`. +11. **CLI.** Options after a subcommand now belong to it (`qodex schedule tick --json` and every + new `--json` flag silently printed text before). + +``` +src/tools/browser/* (dedicated browser: manager, launcher, snapshot, 28 tools, CLI) +src/tools/computer/* (desktop backends: macOS, X11, Wayland, Windows; 15 tools) +src/missions/* (store, planner, runner, daemon, tools, CLI, Telegram adapter) +src/sentinel/*, src/vault/* (guard, policy, injection fencing, audit; encrypted vault, TOTP) +src/control/* (event bus, approval broker, control center server + dashboard) +src/workflows/* (recorder, replay, store, skill generation, tools, CLI) +src/channels/telegram/* (bot, Bot API client, pairing, formatting, CLI) +src/config/agent-config.ts, src/config/paths.ts (new optional config sections + paths) +``` + ## v2.7.0 — 2026-08-14 **Raw telemetry from 2.6 becomes something you can act on — without a slower CLI start.** diff --git a/README.md b/README.md index 4d9562a..59e552e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ curl -fsSL https://raw.githubusercontent.com/QodeXcli/QodeX/main/install.sh | ba qodex setup && qodex ``` -**Version 2.7.0** · 100+ tools · self-improving · phone-driveable · English & Persian · Apache-2.0 +**Version 3.0.0** · 150+ tools · its own browser · desktop control · background missions · self-improving · phone-driveable · English & Persian · Apache-2.0 [![Release](https://img.shields.io/github/v/release/QodeXcli/QodeX?color=blue&label=release)](https://github.com/QodeXcli/QodeX/releases/latest) [![CI](https://github.com/QodeXcli/QodeX/actions/workflows/ci.yml/badge.svg)](https://github.com/QodeXcli/QodeX/actions/workflows/ci.yml) @@ -20,6 +20,34 @@ qodex setup && qodex [![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](package.json) [![Docs](https://img.shields.io/badge/docs-live-blue.svg)](https://qodexcli.github.io/QodeX/) +## New in 3.0 — your agent gets its own computer + +QodeX is no longer only a coding agent. It now has a **dedicated browser** with persistent +logins, **controls your desktop** (macOS, Linux, Windows), runs **missions that keep working +after you close it**, and never buys, pays, sends or types a password **without your +approval** — even in auto mode (`/auto on`). Full guide: **[docs/AGENT_PLATFORM.md](docs/AGENT_PLATFORM.md)**. + +```bash +qodex browser open https://mail.example.com # log in once — the agent stays logged in +qodex "find me 3 flights Tehran→Istanbul under 15M toman next Friday and compare them" +qodex mission start "every morning, summarize new issues in my repos and draft replies" +qodex control --lan # watch it live from your phone, take over, approve +qodex vault add github --origin github.com --username me@example.com --totp +qodex workflow record invoice --url https://billing.example.com # teach it once, replay forever +qodex telegram setup # approvals + missions from Telegram +``` + +- **Dedicated QodeX Browser** — persistent profiles, multi-tab, accessibility snapshots with element refs, set-of-marks screenshots, downloads/uploads, PDF, CDP attach to your own Chrome, and an autonomous `browser_agent` for long multi-page jobs. +- **Desktop control everywhere** — screenshots, click/drag/scroll, Unicode (Persian) typing, clipboard, open apps, window focus, and `computer_use_locate` (describe an element, vision finds it). +- **Missions** — plan → sub-agents → milestones → report, in a detached, resumable worker with its own live view; schedule them as routines. +- **Sentinel** — purchases, payments, sending and credentials always need a human; domain allow/block lists; web/window text fenced as untrusted data with English + Persian prompt-injection detection; full audit log. +- **Vault** — encrypted credentials the model never sees, filled only on their own site (anti-phishing), with TOTP 2FA codes. +- **Control center** — token-protected web page: live browser view, human takeover, one-tap approvals, activity timeline, steering, missions. +- **Workflows** — learn a task from a demonstration, replay it with self-healing selectors at zero model tokens per step. Record in a logged-in browser profile with `workflow record --browser-profile

` (`--profile` is always the config overlay). +- **Telegram** — approve actions, start and follow missions from your phone. + +--- + --- ## Highlights @@ -60,7 +88,7 @@ QodeX takes the opposite stance: **protect the model.** A layer of deterministic - **Syntax gate** — every edit is parsed before it's written; broken syntax is rejected, not saved. - **Completion gate** — the model can't claim "tests pass" or "I fixed it" unless a test actually ran / an edit actually succeeded. Unsupported claims get bounced back for correction. - **Auto-verification** — after the model thinks it's done, QodeX detects the project type and runs the real checker (`tsc`, `eslint`, `ruff`, `pyright`, `go vet`, `cargo`, `php -l` …) on touched files and force-feeds any errors back. -- **Interactive edit approval** — see a red/green diff and Accept / Edit / Continue / Reject before anything hits disk (or `/auto on` to skip). +- **Interactive edit approval** — see a red/green diff and Accept / Edit / Continue / Reject before anything hits disk (or Shift+Tab to `edits` / `auto` to skip — see [Approval modes](#approval-modes)). - **Git-backed sandbox** — risky work runs on a hidden branch with checkpoints; auto-snapshot (`git stash`) before destructive commands, one command to roll back. - **Process sandbox (Docker)** — a second, different isolation: the *shell* runs in a container so a remote-ish turn cannot `rm` your home directory. Pair it with `--profile cloud`. Not a Hub client — Hub is for approvals; this is where commands actually execute. - **Skill security scanner** — skills installed from GitHub are scanned for prompt injection, secret exfiltration, destructive shell, and hidden-unicode payloads *before* they touch disk. @@ -513,7 +541,17 @@ export FIRECRAWL_API_KEY=fc-... # set FIRECRAWL_SCRAPE_CONTENT=1 for in /network Diagnose internet + Ollama + LM Studio connectivity /tools [--all] List registered tools by category /plan /normal Plan mode (read-only) / back to normal -/auto on|off Auto-approve permissions +/auto [manual|edits|auto] Approval mode (also /mode; Shift+Tab cycles) — see "Approval modes" +/status Approval mode, strict mode, session +/goal [--check ""] [--max N] Keep working until the goal is proven (/goal · /goal clear) +/stop [all] Emergency stop: running task, side runs, dev servers (all: missions too) +/learn [name] Turn the task you just finished into a reusable skill +/allow · /mail Standing reply grants · mail watcher, rules, auto-reply (docs/MAIL.md) +/mods · /mod new Mods: hook QodeX itself; have QodeX write one (docs/MODS.md) · /reload-mods +/context-bar What fills the context window (built-in mod) +/instructions first|all Which project instruction files load (QODEX.md, CLAUDE.md, AGENTS.md, GEMINI.md…) +/checkup prompt-audit Audit instruction files, skills, commands → PROMPT_AUDIT.md + patch (nothing applied) +/model opus|sonnet|haiku|fable Latest model of each line /model Override model for this conversation /subagents off|sequential|parallel /snapshot list|take|restore Manage auto-snapshots @@ -530,6 +568,80 @@ Plus any custom commands you drop in `.qodex/commands/` as markdown. From the shell: `qodex sessions list|show |export |search `. Safe shell that should skip the approval hub: `execution.allow` in `config.yaml` (`git status`, `npm test`, …). +## Approval modes + +Three modes decide what QodeX asks before it acts. **Shift+Tab** cycles them in the TUI; the +status bar always shows the current one (`/status` prints it). + +| Mode | What runs without asking | What still asks | +|---|---|---| +| `manual` (default) | read-only tools, `execution.allow` / `autoApprove` matches | file edits, shell, MCP tools, missions, Sentinel actions | +| `edits` | + every file edit (with its diff shown) | shell, MCP tools, missions, Sentinel actions | +| `auto` | everything inside the project: edits, shell, installs, `git commit` / `rebase` / ordinary `push`, deleting project files, MCP and browser/desktop work Sentinel rates non-critical | see below | + +**What auto mode still asks a human for** (with nobody at the terminal — `-p` runs, schedules, +detached missions — the question goes to the control center / Telegram / the mission's approval +queue when one is connected, and is refused otherwise; it is never answered "yes" for you): + +- **Purchases, payments, passwords / credentials, sending messages** and changes to QodeX's own + safety settings — Sentinel-critical, a human answers in every mode. +- **Destructive actions outside the project**: deleting or overwriting paths outside the workspace + roots, force-pushes and remote branch deletes, deleting remote data (cloud, Kubernetes, + `terraform destroy`, databases on other hosts, package unpublish), publishing (`npm publish`, + `docker push`, production deploys), system-level commands (`sudo`, `shutdown`, disks); on the + web, deleting data or changing an account on a non-local site. +- **Writes to the agent's own instruction files** — `AGENTS.md`, `QODEX.md`, `CLAUDE.md`, + `GEMINI.md`, `AI.md`, `.cursorrules`, `.windsurfrules`, `.github/copilot-instructions.md`, the + project's `.qodex/` and `.cursor/rules/`, `~/.qodex/skills|rules|hooks|memory`. These ask in + **every** mode (edit tools and shell alike) so a prompt-injected page can never rewrite the + agent's standing orders; no allow rule or "always yes" covers them. + +The agent's **own questions** are not asked in auto mode either: `ask_user` and plan approval +(`present_plan`) return "decide yourself", so the model picks a sensible default, keeps going and +lists its assumptions in the final answer. A plan presented in plan mode is approved and carried +out in the same turn. + +**Turning it on:** Shift+Tab, `/auto on` (or `/auto auto`, `/mode auto`), `qodex --auto` / +`qodex --approval-mode auto` (TUI and `-p`; `-y`/`--yes` means the same for a `-p` run), or +`approval.defaultMode: auto` in **`~/.qodex/config.yaml`** — only the user config counts; a +project's `.qodex/config.yaml` can never switch you into auto. Missions follow the session mode +(`qodex mission start … --auto`). Answering **always yes** to a prompt switches the session to auto +(a Sentinel "always" stays limited to that category on that site). When the mode changes mid-task +the running agent is told. + +```yaml +# ~/.qodex/config.yaml +approval: + defaultMode: auto # manual | edits | auto + extraRoots: # more folders auto mode treats as "the project" (cwd and the temp dir always count) + - ~/code/shared-libs +``` + +Your `security.denyRules` and the hard-deny patterns still refuse in every mode, and budgets +(`--budget-usd`, per-task caps) still stop a run — auto mode never raises them. + +## Mail, password vault and CAPTCHAs + +- **Mail** — connect any mailbox (`qodex mail add`), read, draft and send with your approval; standing + reply grants you create yourself; a watcher that wakes up on new mail and runs the tasks you assigned. + See [docs/MAIL.md](docs/MAIL.md). +- **Password vault** — logins the agent can use but never read: OS-keychain key, imports from Chrome / + Firefox / Bitwarden / 1Password, one-step `browser_login` with 2FA, strong passwords on sign-up, logins + you type into a secure prompt, "save this login?" after you log in yourself. See + [docs/VAULT_AND_CAPTCHA.md](docs/VAULT_AND_CAPTCHA.md). +- **CAPTCHAs** — QodeX never solves them; it waits out self-clearing checks and hands the rest to you + (Telegram card with a one-tap live-view link, solve it from your phone), then continues by itself. +- **Web Bot Auth** (`browser.botAuth`, off by default) — the honest alternative to stealth: QodeX signs its + own requests with an Ed25519 key (RFC 9421) so a site can recognise the agent and let it through, instead + of hiding that it is automated. `qodex browser bot-auth --init`; no fingerprint spoofing. See + [docs/VAULT_AND_CAPTCHA.md](docs/VAULT_AND_CAPTCHA.md). + +## Mods (Claude Code-compatible) + +Small JS/TS modules in `~/.qodex/mods` that hook QodeX itself — rewrite or hold tool calls, draw above the +prompt, add commands and tools, run timers. `/mod new ` has QodeX write one (it asks +before writing). Project mods load only after `qodex mod trust`. See [docs/MODS.md](docs/MODS.md). + ## End-to-end example ``` @@ -586,7 +698,7 @@ One transport-agnostic gateway does all the work; the platform adapters are thin | `/new` | fresh conversation (new session) | | `/stop` | abort the running task | | `/status` | running/queued · model · project · session · auto state | -| `/auto on \| off` | auto-approve actions (skip the buttons) — handy on mobile, off by default | +| `/auto on \| off` | auto mode for this chat (skip the buttons) — purchases, payments, passwords, sending messages and destructive actions outside the project still ask; off by default | | `/model [id]` | show or switch the model for this conversation | | `/sessions` · `/resume ` | list past sessions and continue one (same store as the CLI) | | `/episodes` | past tasks solved here, from episodic memory | @@ -621,6 +733,11 @@ qodex schedule add --name nightly-deps \ qodex schedule list · runs · enable/disable · rm ``` +**Monitors that remember.** `--continuity` gives each run the previous run's answer so it reports +only what changed; `--notify-on-change` skips the notification / chat delivery when the answer is +the same as last time (`qodex schedule add --name price --cron @hourly --prompt "price of X at +shop.example" --continuity --notify-on-change`). + **Deliver results to chat.** `--deliver telegram:` (or `discord:` / `slack:`) posts each run's outcome to your phone — the scheduler talks to the platform REST API directly, so it needs no running bot. A recipe's verdict line leads the message. **Autonomous *Verified* PR — the differentiator.** `--recipe verified-pr` doesn't just run a prompt; it wraps your goal in an unattended-safe **protocol**: diff --git a/docs/AGENT_PLATFORM.md b/docs/AGENT_PLATFORM.md new file mode 100644 index 0000000..abf8069 --- /dev/null +++ b/docs/AGENT_PLATFORM.md @@ -0,0 +1,366 @@ +# QodeX Agent Platform — your agent's own computer + +QodeX 3.0 turns the coding CLI into a general autonomous agent that does real work +on the web and on your desktop, keeps working in the background, and asks you before +anything consequential — while staying local-first and model-agnostic (it works with +local Qwen/Llama models as well as Claude, GPT, Gemini and DeepSeek). + +It is built in the spirit of personal agents like Meta Muse and xAI Grok Bot: an agent with +its **own computer** that plans, browses, fills forms, keeps working in the background and +checks in only when it needs you. Unlike them, QodeX runs on **your** machine, with **your** +choice of model, and also controls your desktop. + +| Capability | QodeX 3.0 | +|---|---| +| Own browser with persistent logins | local persistent profiles, or attach to your Chrome over CDP | +| Desktop control | macOS, Linux (X11 + Wayland), Windows | +| Keeps working after you close the app | detached, resumable missions with milestones and a final report | +| Guard for purchases / payments / sending / credentials | Sentinel — cannot be bypassed by auto mode or `--yes` | +| Credentials the model never sees | encrypted vault, origin-bound (anti-phishing), TOTP | +| Prompt-injection defense for web content | English + Persian detection, page text fenced as data | +| Live view + human takeover | token-protected web control center | +| Approve from your phone | Telegram channel (or the control center over LAN/tunnel) | +| Learn a task from a demonstration | record → self-healing replay → reusable skill | +| Scheduled routines | `qodex schedule add --mission` | + +--- + +## 1. The dedicated QodeX Browser + +A persistent Chromium profile that belongs to the agent (`~/.qodex/browser/profiles/`): +cookies and logins survive restarts, so you sign in once and the agent stays signed in. + +```bash +qodex browser open https://mail.example.com # visible window — log in once yourself +qodex browser status # executable, profile, tabs +qodex browser profiles # list profiles (work / personal / ...) +qodex browser close +``` + +Inside a session: `/browser`, `/browser open `, `/browser headless`, `/browser profile work`. + +**How the agent sees pages.** `browser_snapshot` returns the page's accessibility tree with +stable element refs (`button "Add to cart" [ref=e12]`); actions target refs, not guessed CSS. +Every action returns what changed (URL, new tabs, dialogs, downloads) plus a fresh compact +snapshot, so a model needs one call per step. + +**Tools (28):** `browser_navigate, browser_snapshot, browser_click, browser_type, browser_fill, +browser_fill_form, browser_select, browser_hover, browser_press, browser_scroll, browser_drag, +browser_upload, browser_history, browser_tabs, browser_extract (markdown/text/links/tables/ +metadata), browser_screenshot (set-of-marks overlay + optional vision analysis), browser_pdf, +browser_downloads, browser_dialog, browser_console, browser_network, browser_evaluate, +browser_get_text, browser_wait_for, browser_status, browser_close, browser_fill_secret, +browser_agent` (an autonomous browser sub-agent for long multi-page jobs). + +**Finding a browser.** QodeX discovers a usable Chromium on its own (Playwright caches, system +Chrome / Chromium / Edge / Brave) — even when the installed Playwright expects a different +revision. Override with `browser.executablePath` or `QODEX_BROWSER_EXECUTABLE`. + +**Use your own Chrome instead:** start Chrome with `--remote-debugging-port=9222` and set +`browser.cdpUrl: http://127.0.0.1:9222` (or `QODEX_BROWSER_CDP_URL`). QodeX opens its own tab +and only disconnects on close — it never quits your browser. + +**Lean mode** (`browser.lean`, default `auto`). When nobody is looking at the browser (QodeX +launched it headless: missions, schedules, `--print`), it skips images, fonts and audio/video. +The DOM, scripts, styles, forms, cookies and the HTTP cache are untouched, so snapshots, clicks +and sign-ups work the same. On a 12-photo gallery page it downloaded ~0 MB instead of 5 MB, +loaded in ~270 ms instead of ~720 ms and used ~100–180 MB less memory. It never applies to +your own Chrome (`cdpUrl`) or to localhost / LAN pages (dev servers), and it turns itself off +for the rest of the session as soon as pixels matter: a screenshot, a takeover, the live view +or a bot check. `browser_status` shows it; `lean: on` also uses it in a visible window, `off` +never; `QODEX_BROWSER_LEAN=1|0` forces it. It is not a way to look less automated: it changes +nothing a site sees about the browser. + +```yaml +# ~/.qodex/config.yaml +browser: + headless: auto # visible window at the TUI, headless otherwise; QODEX_BROWSER_HEADED=1 to watch + lean: auto # auto (headless only) | on | off + profile: default + viewport: { width: 1280, height: 800 } + dialogPolicy: accept # accept | dismiss | ask + snapshotAfterAction: true + agentMaxSteps: 40 +``` + +## 2. Desktop control — macOS, Linux, Windows + +`computer_use_*` tools drive the real desktop: screenshot, click, double-click, drag, scroll, +type (Unicode / Persian via clipboard paste), key combos, clipboard, open apps/files/URLs, list +and focus windows, and `computer_use_locate` (describe an element → vision model returns its +coordinates). `computer_use_agent` runs an autonomous desktop sub-agent. + +Coordinates are **screenshot pixels**; QodeX maps them to the screen (Retina/HiDPI scaling and +window-only captures included) and rejects coordinates outside the last screenshot. + +| Platform | Needs | +|---|---| +| macOS | Accessibility + Screen Recording permission for your terminal; `cliclick` optional | +| Linux X11 | `xdotool`, `scrot` (or ImageMagick `import`), `xclip`, `wmctrl` | +| Linux Wayland | `ydotool` ≥ 1.0 with `ydotoold`, `grim`, `wl-clipboard` | +| Windows | nothing extra (PowerShell) | + +`/desktop` prints the detected backend and the exact install command for anything missing. + +## 3. Missions — work that continues in the background + +```bash +qodex mission start "Every listing under 30M toman on divar for a used MacBook Air M2 — compare and shortlist 5" +qodex mission list +qodex mission attach m1a2b3c4d # follow live; type to steer or answer approvals +qodex mission status m1a2b3c4d # steps, milestones, cost, live-view link +qodex mission approve m1a2b3c4d # or deny / cancel / resume / steer +``` + +A mission is planned into steps (with dependencies), each step runs on a fresh agent with its +own session, milestones are reported as it goes, failed steps retry with the error fed back, +and a final report is written. The worker is a **detached process**: close QodeX, close the +terminal — it keeps going. Cancel is graceful; a reboot pauses the mission and `resume` picks +it up from the last finished step. Each worker starts its own private **live view** (see §5), +shown in `mission status`. + +From a session: `/mission `, `/missions`, or let the agent call `mission_start` itself +for long jobs. Routines: `qodex schedule add --name news --cron "0 8 * * *" --mission --prompt "..."`. +`qodex mission start "…" --auto` (or `--yes`, `--approval-mode auto`) runs the mission in auto +mode — see [Auto mode](#auto-mode--what-still-asks); a mission started from an auto session +inherits it. + +```yaml +missions: + maxConcurrency: 2 + stepMaxIterations: 60 + stepMaxWallSeconds: 1800 + maxCostUsd: 0 # pause and ask once a mission has spent this much (0 = no cap) + maxAttempts: 2 +``` + +## 4. Sentinel — nothing consequential without you + +Every tool call — from the main agent, sub-agents, missions or the MCP server — passes +through Sentinel at a single choke point. It classifies the action (English **and** Persian +labels, page URL, form action, payment gateways like Shaparak/Zarinpal/Stripe, secrets such as +card numbers via Luhn, Sheba/IBAN, API keys): + +| Category | Default | +|---|---| +| **purchase, payment, credential, send** | **critical** — always needs an explicit human answer. Auto mode (`/auto on`, `--auto`, `--yes`) can't approve these. With no human reachable the action is refused (`[SENTINEL_BLOCKED]`). | +| delete, account, upload, publish, desktop | asks through the normal permission flow ("always for this site" remembered per session). In auto mode these run without asking, except deleting data / changing an account / publishing on a non-local site and uploading a file from outside the project | +| navigation | blocked/allowed domains, optional private-network block | + +### Auto mode — what still asks + +QodeX has three approval modes (Shift+Tab cycles them; the status bar shows the current one): +`manual` asks before edits and shell, `edits` lets file edits through, and **`auto`** works +without asking. In auto mode everything inside the project is automatic — edits, shell, +installs, commits, ordinary pushes, deleting project files, browser and desktop work that +Sentinel rates non-critical. Only these still stop for a human: + +- **purchases, payments, passwords / credentials, sending messages** (and QodeX's own safety + settings) — Sentinel-critical, as in every mode; +- **destructive actions outside the project** — deleting or overwriting paths outside the + workspace roots, force-push / remote branch deletes, deleting remote data (cloud, Kubernetes, + `terraform destroy`, other hosts' databases, package unpublish), publishing (`npm publish`, + `docker push`, production deploys), system-level commands (`sudo`, `shutdown`, disks), and on + the web deleting data or changing an account on a non-local site; +- **writes to the agent's own instruction files** — `AGENTS.md`, `QODEX.md`, `CLAUDE.md`, + `GEMINI.md`, `AI.md`, `.cursorrules`, `.windsurfrules`, `.github/copilot-instructions.md`, + anything under the project's `.qodex/` or `.cursor/rules/`, and `~/.qodex/skills|rules|hooks|memory`. + A prompt-injected page that got the agent to rewrite one would persist into every later + session, so these ask in **every** mode, by edit tool or by shell (`>>`, `tee`, `cp`, `sed -i`, + `rm`…). No allow rule or "always yes" covers them; your "yes for this session" on that exact + write does. + +With no human at the terminal (`-p`, schedules, detached missions) those questions go to the +control center, Telegram or the mission's approval queue, and are refused when none is +connected — never answered "yes" automatically. The agent's own questions (`ask_user`, plan +approval) are not asked in auto mode: it decides, continues and lists its assumptions at the end. +Sub-agents, side runs and missions started from an auto session follow the same policy. + +Turn it on with Shift+Tab, `/auto on` (or `/mode auto`), `qodex --auto` / +`qodex --approval-mode auto` (`-y` means the same for `-p` runs and `mission start`), or as the +default in **your user config** (a project's `.qodex/config.yaml` cannot switch you into auto): + +```yaml +# ~/.qodex/config.yaml +approval: + defaultMode: auto # manual | edits | auto + extraRoots: [~/code/shared-libs] # also "the project" for auto mode (cwd + temp dir always are) +``` + +`security.denyRules`, the hard-deny patterns and budgets still apply in auto mode. + +Web and window text is **untrusted data**: it is wrapped in `` and scanned +for prompt injection (English and Persian, hidden Unicode); detections are flagged to the model +and on the bus. Every decision goes to `~/.qodex/sentinel/audit.jsonl` (secrets redacted). + +```yaml +sentinel: + requireApproval: [purchase, payment, credential, send] + autoApprove: [] # e.g. [download] + blockedDomains: [bank.example] + allowedDomains: [] # non-empty = allow-list + blockPrivateNetwork: false + remoteApprovalTimeoutSec: 600 +``` + +`/sentinel` shows status and recent decisions; `/sentinel reset` clears session approvals. +Local dev targets (localhost / LAN) are never escalated to critical, so testing your own +checkout flow stays smooth. + +### The vault — logins the model never sees + +```bash +qodex vault add github --origin github.com --username me@example.com --totp # secret read hidden +qodex vault list +``` + +The agent fills credentials with `browser_fill_secret` — the value never enters the +conversation, logs or the audit trail. Fills only happen on the entry's own origin (https +only, except localhost), only into the right kind of field, and the origin is re-checked right +before typing — a phishing clone gets `[VAULT_ORIGIN_MISMATCH]`. TOTP codes (RFC 6238) are +generated on the fly. Encrypted with AES-256-GCM; the key lives in a separate 0600 file. + +## 5. Control center — watch, take over, approve + +```bash +qodex control # local; prints a private link with a token +qodex control --lan # reachable from your phone on the same Wi-Fi +qodex control --tunnel # public https link via cloudflared/ngrok (still token-protected) +``` + +or `/control` inside a session. The page shows the agent's browser **live**, lets you +**take over** (your clicks/keys go to the page; the agent waits — also `/takeover`), answer +**approvals** with one tap, follow an **activity timeline**, **steer** the running task, and +see/cancel **missions**. English and Persian UI. Always token-gated (HttpOnly SameSite=Strict +cookie, constant-time comparison, origin checks on writes). + +## 6. Workflows — learn by demonstration + +```bash +qodex workflow record invoice --url https://billing.example.com # a window opens; do the task once, press Enter +qodex workflow run invoice --param month=2026-09 +qodex workflow list +``` + +or ask the agent ("record this as a workflow"). Recording captures the agent's or your actions +with robust selectors (id → data-testid → name → role+name → css), turns typed values into +`{{params}}` and password/CVV/OTP fields into secret params (never stored). Replay heals broken +selectors (role/name → text → label), asks Sentinel before consequential steps, can fill +secrets from the vault (`vault:`), and costs zero model tokens per step. Each workflow +is also saved as a skill so the agent rediscovers it. `record --browser-profile ` records +in a named browser profile (`--profile` is QodeX's config overlay). + +## 7. Your agent in your pocket — Telegram, Discord, Slack, WhatsApp, Signal + +**Chat with the agent** through the bot gateway (`qodex bot`, see the README): send tasks, +watch them stream, and answer approvals with inline buttons. It now also drives the agent +platform: + +| Command | What it does | +|---|---| +| `/mission ` | start a background mission (keeps going after you close the chat) | +| `/missions` | missions, progress, and approvals waiting for you | +| `/approve ` · `/deny ` | answer a mission's approval (e.g. a purchase Sentinel paused) | + +Sentinel's critical prompts in a bot conversation arrive as buttons in that chat. + +**Approvals-only notifier.** `qodex telegram` is a lightweight, pairing-based Telegram bot +for people who don't run the chat gateway: it delivers approvals (with buttons) and +milestones from detached missions and other QodeX processes, `/mission`, `/missions`, +`/cancel `, `/status` and `/screen` (a screenshot of the agent's browser). + +```bash +qodex telegram setup # paste the BotFather token (stored in ~/.qodex/.env) +qodex telegram pair # prints a one-time code; send /pair to your bot +qodex telegram start # runs the notifier (or /telegram start inside a session) +``` + +Private chats only, pairing codes expire, brute-force lockout; Persian and English. +Telegram allows **one** poller per bot token — if you also run `qodex bot`, give the notifier +its own bot and point `telegram.botTokenEnv` at that token's variable. + +## 8. Goals, emergency stop, /learn and monitors + +**Standing goals — keep going until it is actually done.** `/goal ` +starts a task and keeps QodeX working on it across turns until the goal is proven, not merely +claimed: + +``` +/goal all tests pass and the build is green --check "npm test && npm run build" --max 10 +/goal the README documents every CLI flag # no check: the model must cite evidence +/goal # show the goal and its rounds /goal clear # drop it +``` + +After each run QodeX checks: with `--check`, the command must exit 0; without one, the final +answer must cite evidence on a `GOAL_MET: …` line. If not met, it starts another round with the +check's output (up to `--max`, default 8, max 50) and then stops and says what is missing. + +**Emergency stop.** `/stop` halts everything this QodeX process is doing — the running task, +side runs, background jobs and dev servers — and clears the standing goal. It works mid-task +(it is not queued as a steering note). `/stop all` also cancels every active mission. The same +stop is on the control center (the red **⏹ Stop** button, missions included) and in Telegram +(`/stop`, `/stop all`). + +**`/learn [name]` — keep what just worked.** Turns the task you just finished (its request, the +ordered tool steps, the files it changed, the outcome) into an active skill under +`~/.qodex/skills//`, with the same deterministic distiller the automatic flywheel uses. A +skill you wrote yourself with that name is never overwritten. Use it with `/`. + +**Monitors — schedules that remember.** `qodex schedule add … --continuity` hands each run the +previous run's answer so it reports what changed; `--notify-on-change` skips the notification / +chat delivery when the answer is the same as last time (the run is still logged): + +```bash +qodex schedule add --name gpu-price --cron "@hourly" \ + --prompt "check the price of the RTX 5090 at shop.example" \ + --continuity --notify-on-change --deliver telegram: +``` + +--- + +### For weaker local models + +The platform is built to *protect* small models: refs instead of selectors, compact +snapshots after every action, loop guards that understand changing page state, a completion +gate that only accepts "I ordered it" when an action actually succeeded, and dedicated +browser/desktop operator roles with tight prompts. Sub-agents run on fresh agent instances +with their own session and budget. + +### Where things live + +``` +~/.qodex/browser/profiles/ persistent browser profiles +~/.qodex/browser/downloads files the agent downloaded +~/.qodex/screenshots browser + desktop screenshots +~/.qodex/missions/.log mission worker logs (state is in sessions.db) +~/.qodex/workflows/.json recorded workflows +~/.qodex/sentinel/audit.jsonl Sentinel decisions +~/.qodex/vault.json + .vault-key encrypted credentials (0600) +~/.qodex/channels/telegram.json paired chats +``` + +--- + +## خلاصه فارسی + +**QodeX حالا یک ایجنت خودمختار کامل است، نه فقط یک ابزار کدنویسی:** + +- **مرورگر اختصاصی** با پروفایل دائمی — یک بار لاگین کنید، ایجنت لاگین می‌ماند. `qodex browser open` +- **کنترل دسکتاپ** روی مک، لینوکس و ویندوز (اسکرین‌شات، کلیک، تایپ فارسی، کلیپ‌بورد، باز کردن برنامه). +- **مأموریت‌های پس‌زمینه** که بعد از بستن برنامه هم ادامه می‌دهند: `qodex mission start "..."` +- **Sentinel**: خرید، پرداخت، ارسال پیام و ورود اطلاعات حساس بدون تأیید شما انجام نمی‌شود — حتی با `/auto on` یا `--yes`. محتوای صفحات وب «داده» حساب می‌شود و تزریق دستور (فارسی و انگلیسی) شناسایی می‌شود. +- **حالت خودکار (auto)**: سه حالت تأیید داریم — `manual` (پیش‌فرض)، `edits` و `auto`؛ با Shift+Tab عوض می‌شوند و نوار وضعیت حالت فعلی را نشان می‌دهد. در حالت auto هر کاری داخل پروژه (ویرایش، شل، نصب پکیج، کامیت و push معمولی، حذف فایل‌های پروژه) بدون پرسش انجام می‌شود و ایجنت سؤال‌های خودش را هم نمی‌پرسد: خودش تصمیم می‌گیرد و فرض‌هایش را در پایان می‌گوید. فقط این‌ها هنوز تأیید شما را لازم دارند: خرید، پرداخت، رمز عبور، ارسال پیام، و کارهای مخرب بیرون از پروژه (حذف فایل بیرون از پروژه، force-push، حذف داده‌ی راه‌دور، انتشار پکیج، sudo). اگر کسی پای ترمینال نباشد این موارد به مرکز کنترل / تلگرام می‌روند یا رد می‌شوند. روشن کردن: Shift+Tab، `/auto on`، `qodex --auto`، یا `approval.defaultMode: auto` فقط در `~/.qodex/config.yaml` (تنظیمات پروژه نمی‌تواند شما را به auto ببرد). `approval.extraRoots` پوشه‌های دیگری را جزو پروژه حساب می‌کند. قوانین deny و بودجه‌ها همچنان اعمال می‌شوند. +- **فایل‌های دستورالعمل ایجنت** (`AGENTS.md`، `QODEX.md`، `CLAUDE.md`، پوشهٔ `.qodex/`، `~/.qodex/skills` و …) در **همهٔ** حالت‌ها، حتی auto، فقط با تأیید شما تغییر می‌کنند — تا صفحه‌ای که تزریق دستور دارد نتواند قوانین دائمی ایجنت را بازنویسی کند. +- **هدف ماندگار** (`/goal`): ایجنت تا وقتی هدف واقعاً ثابت نشده ادامه می‌دهد — یا دستور بررسی (`--check "npm test"`) موفق شود، یا با سطر `GOAL_MET:` مدرک بیاورد؛ حداکثر تعداد دور با `--max`. +- **توقف اضطراری** (`/stop`): کار در حال اجرا، اجراهای جانبی و سرورهای توسعه را فوراً متوقف می‌کند؛ `/stop all` مأموریت‌ها را هم لغو می‌کند. همین دکمه در مرکز کنترل و دستور `/stop` در تلگرام هم هست. +- **یادگیری فوری** (`/learn`): کاری که همین الان انجام شد را به یک مهارت قابل استفادهٔ دوباره تبدیل می‌کند. +- **پایش زمان‌بندی‌شده**: `qodex schedule add … --continuity --notify-on-change` — هر اجرا جواب اجرای قبلی را می‌بیند و فقط وقتی چیزی عوض شده خبر می‌دهد. +- **ایمیل**: اتصال به هر صندوق ایمیل، خواندن، پیش‌نویس و ارسال با اجازهٔ شما؛ «مجوز دائمی پاسخ» را فقط خودتان می‌سازید؛ با رسیدن ایمیل جدید بیدار می‌شود و کارهایی را که از قبل سپرده‌اید انجام می‌دهد. راهنما: docs/MAIL.md +- **کپچا**: QodeX کپچا را هرگز خودش حل نمی‌کند؛ بررسی‌هایی را که خودشان رد می‌شوند صبر می‌کند و بقیه را با یک کارت تلگرام و لینک یک‌لمسی به شما می‌سپارد تا از گوشی حلش کنید، و بعد خودش ادامه می‌دهد. stealth به‌طور پیش‌فرض خاموش است. +- **Mods**: ماژول‌های کوچکی که خودِ QodeX را تغییر می‌دهند (سازگار با mods در Claude Code)؛ `/mod new` تا QodeX برایتان بسازد. راهنما: docs/MODS.md +- **گاوصندوق رمزها**: کلید در Keychain سیستم‌عامل، وارد کردن از Chrome/Firefox/Bitwarden/1Password، ورود یک‌مرحله‌ای با کد دومرحله‌ای، ساخت رمز قوی هنگام ثبت‌نام، و تایپ رمز توسط خودتان در فرم امن — ایجنت رمز را هرگز نمی‌بیند و فقط روی سایت اصلی پر می‌کند (ضد فیشینگ). راهنما: docs/VAULT_AND_CAPTCHA.md +- **هویت صادقانهٔ ایجنت (Web Bot Auth)** (`browser.botAuth`، پیش‌فرض خاموش): QodeX درخواست‌های خودش را با کلید Ed25519 امضا می‌کند تا سایت بفهمد این ایجنت است و اجازهٔ عبور بدهد — برعکسِ پنهان‌کاری. اثرانگشت جعل نمی‌شود و رفتار انسانی ساخته نمی‌شود. کلید خصوصی از دستگاه خارج نمی‌شود و Sentinel ایجنت را از آن دور نگه می‌دارد. راهنما: docs/VAULT_AND_CAPTCHA.md +- **حالت سبک مرورگر** (`browser.lean`): وقتی کسی مرورگر را نگاه نمی‌کند (اجرای بدون پنجره)، تصویر، فونت و ویدیو دانلود نمی‌شود؛ صفحه، اسکریپت‌ها، فرم‌ها، کوکی‌ها و کش دست‌نخورده می‌مانند. در یک صفحهٔ ۱۲ عکسی: ۰ به‌جای ۵ مگابایت دانلود، ۲۷۰ به‌جای ۷۲۰ میلی‌ثانیه و ۱۰۰ تا ۱۸۰ مگابایت حافظهٔ کمتر. روی localhost و Chrome خودتان اعمال نمی‌شود و با اسکرین‌شات، در دست گرفتن کنترل، نمای زنده یا کپچا خودش خاموش می‌شود. +- **مرکز کنترل وب**: تماشای زنده‌ی مرورگر ایجنت، در دست گرفتن کنترل، تأیید با یک کلیک — حتی از گوشی. `qodex control --lan` +- **یادگیری از نمایش**: یک بار کار را انجام دهید، QodeX ضبط و بعداً تکرار می‌کند. `qodex workflow record` +- **تلگرام / دیسکورد / اسلک / واتس‌اپ / سیگنال**: گفتگو با ایجنت، شروع مأموریت (`/mission`) و تأیید اقدامات از گوشی (`qodex bot` یا `qodex telegram`). diff --git a/docs/MAIL.md b/docs/MAIL.md new file mode 100644 index 0000000..b960971 --- /dev/null +++ b/docs/MAIL.md @@ -0,0 +1,111 @@ +# Mail (IMAP / SMTP) + +QodeX can read your mailboxes, write drafts and — with your approval — send mail. + +## Add an account + +```sh +qodex mail add personal --email you@gmail.com # preset detected from the address +qodex mail add work --email you@corp.example --imap mail.corp.example:993 --smtp mail.corp.example:465 +qodex mail test personal # signs in to IMAP and SMTP, changes nothing +qodex mail list | qodex mail default work | qodex mail remove work | qodex mail presets +``` + +The password is typed with echo off, or read from the first line of stdin +(`printf '%s\n' "$APP_PW" | qodex mail add personal --email you@gmail.com`). It is never a +command-line argument. `--oauth-token` stores an OAuth2 access token (XOAUTH2) instead. + +### App passwords — گذرواژهٔ برنامه + +Most providers refuse your normal password over IMAP/SMTP once two-step sign-in is on. Create +an **app password** (a separate password only mail apps can use) and enter that. + +| Provider | Preset | Where to get an app password | +|---|---|---| +| Gmail / Google Workspace | `gmail` | 2-Step Verification on → https://myaccount.google.com/apppasswords (enable IMAP in Gmail settings) | +| Outlook.com / Hotmail | `outlook` | OAuth2 token (`--oauth-token`) or https://account.live.com/proofs/AppPassword while offered | +| Microsoft 365 | `office365` | admin must allow IMAP + SMTP AUTH; usually OAuth2 | +| Yahoo | `yahoo` | Account security → Generate app password | +| iCloud | `icloud` | account.apple.com → Sign-In and Security → App-Specific Passwords | +| Yandex | `yandex` | enable IMAP in Mail settings → id.yandex.com/security/app-passwords | +| Zoho | `zoho` | enable IMAP; with 2FA: accounts.zoho.com → Security → App Passwords (EU: use custom) | +| Fastmail | `fastmail` | Settings → Privacy & Security → App passwords (IMAP + SMTP) | +| AOL | `aol` | Account Security → Generate app password | +| GMX | `gmx` | enable POP3/IMAP in settings (gmx.net/.de: use custom) | +| Proton Mail | `proton-bridge` | install Proton Mail Bridge; use the user + BRIDGE password it shows (127.0.0.1, plain is allowed only there) | +| anything else | `custom` | `--imap host[:port] --smtp host[:port]` (993/465 = TLS, 143/587 = STARTTLS, required) | + +برای Gmail، Yahoo، iCloud و بیشتر سرویس‌ها با تأیید دومرحله‌ای باید «App Password» بسازید و همان را وارد کنید، نه رمز اصلی حساب. + +## What the agent can do + +| Tool | What it does | Approval | +|---|---|---| +| `mail_list` | newest first: id, from, subject, date, read/unread, snippet | none (output fenced as untrusted) | +| `mail_read` | headers, text body (HTML → text), attachment names | none (output fenced, injection-scanned) | +| `mail_draft` | saves a signed local draft (+ a copy in the server's Drafts); `reply_to_id` keeps the thread | none | +| `mail_send` | sends a draft (or to/subject/body) | **a human, every time** (Sentinel `send`, critical) | +| `mail_mark` / `mail_move` | read/unread/flag; archive/trash/junk/folder | none in auto mode | +| `mail_download_attachment` | saves an attachment into the project, never overwrites | the normal edit policy | + +## Security + +- Accounts and their passwords / tokens live in `~/.qodex/mail-accounts.enc` (0600), encrypted + with the vault key (`~/.qodex/.vault-key`). It is not the credential vault: + `browser_fill_secret` can never type a mail password into a web page. +- Passwords never appear in tool output, errors, logs, the event bus or the audit trail (every + encoding is scrubbed, including base64 AUTH blobs). +- Email content is data, not instructions: Sentinel fences it and flags prompt injection. A + reply to a flagged email is marked in its draft and always needs an explicit human approval. +- Sending always shows the recipients (To / Cc / Bcc), subject, body preview and attachments and + waits for a human — in manual, edits and auto mode. With nobody to ask (headless, a detached + mission) the send is refused. Drafts are immutable and signed, so what was approved is what is + sent, and a draft is never sent twice. +- Attachments from disk: QodeX's own state (`~/.qodex`) and credential files (`.env`, SSH keys, + `.npmrc`, …) are refused. + +### Standing grants, the mail watcher and mail rules + +**Auto-replies (standing grants).** A send always needs your approval, with one exception: a *standing reply grant* that you create yourself. Only these human surfaces can create one: +- TUI `/allow mail-replies [--account work] [--from boss@acme.com,@acme.com] [--max-per-day 50] [--expires 7d]` +- terminal `qodex grant add mail-replies …` +- a paired Telegram chat's `/allow …` +- clicking **"always allow replies like this"** on a mail_send approval prompt + +List grants with `/allow list` or `qodex grant list`. Revoke with `/allow revoke ` or `qodex grant revoke `. + +No tool lets the model create, widen or read a grant. Sentinel blocks the agent from reading or writing `~/.qodex/grants.json`, `~/.qodex/mail-auto/` and `~/.qodex/mail/`. If the agent runs `qodex grant …` or `qodex mail rule add …`, Sentinel treats it as a change to QodeX's own safety settings, which always needs a human. + +A grant covers a send only when all of these hold: +- It is a draft made with `mail_draft reply_to_id` (a signed draft). +- It goes in the same thread to the original sender only. A Reply-To redirect does not count, and there are no cc, bcc or other recipients. +- It has no attachments from disk. +- The original email was not flagged as prompt injection. +- The reply contains no secret. +- The account and sender filter match, the grant has not expired, and the daily cap (default 50) is not used up. + +A covered send needs no prompt, including in a detached run. It is audited (via `grant`), and you are told "Auto-replied to X: subject" in the TUI, the control center, Telegram and a desktop notification. Anything else gets the normal critical prompt, and with no human available it is refused. + +**Watcher.** Commands: +- `qodex mail watch` runs in the foreground; `qodex mail watch --daemon` runs in the background. +- `qodex mail watch --status` and `qodex mail watch --stop`. +- `/mail watch start|stop|status|recent`. + +The watcher uses IMAP IDLE per account, with polling as a fallback. Config: `mail.watch: true` or `{ enabled, accounts, folder, pollIntervalSec, idle }`. With `mail.watch` on, `qodex telegram start` and the control center start it. + +New mail is announced once per message, with sender, subject and a short snippet. Messages are deduplicated by Message-ID, and the last-seen UID is kept per account and folder. Existing mail is never replayed. + +**Rules (standing tasks).** Add one with `qodex mail rule add "" "" [--cwd dir] [--auto]` or `/mail rule add …`. Conditions: +- `from:` +- `to:` +- `subject:"…"` +- `body:"…"` +- `has:attachment` +- `account:` +- `*` for any mail + +Manage rules with `/mail rule list|remove|enable|disable`. On a match, the watcher starts a background run (a mission) in the rule's directory. Its instruction is your task; the email is attached as fenced data, never as instructions. An email flagged as prompt injection gets a draft-only run, and you are notified. + +`qodex mail reply-all [--account a] [--from @acme.com] [--max-per-day N] [--expires 7d]` (or `/mail reply-all`) turns auto-reply on: it creates a reply grant plus a rule "draft a reply and send it". `/mail rule remove ` turns it off and revokes the grant. Auto-reply never answers mail from your own address, mailing lists, bulk mail, autoresponders or bounces. See `/mail status` for an overview. + +**خلاصهٔ فارسی:** ارسال ایمیل همیشه تأیید شما را می‌خواهد. تنها استثنا «مجوز دائمی پاسخ» است که فقط خودتان می‌سازید: با `/allow mail-replies`، با `qodex grant add`، در تلگرام، یا با گزینهٔ «always allow replies like this». این مجوز فقط پاسخ در همان رشته به فرستندهٔ اصلی را پوشش می‌دهد؛ بدون گیرندهٔ اضافه، بدون پیوست، و تنها اگر ایمیل اصلی مشکوک به تزریق دستور نباشد. هر پاسخ خودکار ثبت می‌شود و به شما خبر داده می‌شود. `qodex mail watch --daemon` ایمیل‌های تازه را اعلام می‌کند. `qodex mail rule add` برای ایمیل‌های منطبق یک کار پس‌زمینه شروع می‌کند؛ متن ایمیل فقط داده است و دستور به حساب نمی‌آید. `qodex mail reply-all` پاسخ خودکار را روشن می‌کند. diff --git a/docs/MODS.md b/docs/MODS.md new file mode 100644 index 0000000..dfdbcbd --- /dev/null +++ b/docs/MODS.md @@ -0,0 +1,263 @@ +# Mods — change QodeX itself + +A **mod** is a small JavaScript (or TypeScript) module that hooks into QodeX's own events. +It can hold or rewrite a tool call, rewrite a prompt, draw above or under the prompt, add a +slash command or a tool, call a model, run work on a timer, or leave a heads-up in the +transcript. Skills tell the model *how to work*; MCP servers give the model *tools*; mods +change *QodeX* — the harness around the model. + +The shape follows [Claude Code mods](https://code.claude.com/docs/en/plugins/mods/overview) +(`register(on, options)`, middleware hooks `($, e, next)`, the `$` mods API), so a simple +Claude Code mod runs in QodeX unchanged. [Differences](#claude-code-compatibility) are listed +at the end. + +## Quick start + +```text +/mod new show how full the context is and the time under the prompt +``` + +QodeX writes the mod to `~/.qodex/mods//` with its mod-writing playbook (the +`modsmith` skill), validates it with `qodex mod validate`, and reloads mods. The write asks +you first — in every approval mode, auto included — and that answer is your consent to +install code that runs with your permissions. + +Or write one yourself: + +```text +~/.qodex/mods/hello/mod.json { "name": "hello", "description": "Say hello", "version": "0.1.0" } +~/.qodex/mods/hello/register.js +``` + +```js +export function register(on, options) { + on('session.start', async ($, e, next) => { + await $.command.register({ name: 'hello', description: 'Say hello' }) + return next(e) + }) + on('command.run', { command: 'hello' }, async ($) => { + $.ui.toast('Hello from a mod!') + return {} // nothing in the transcript; { text } prints a line + }) +} +``` + +Then `qodex mod validate ~/.qodex/mods/hello` and `/reload-mods` (user mods also reload when +their files change). + +## Layout and where mods live + +Either layout loads: + +| Layout | Files | +| --- | --- | +| QodeX | `mod.json` (`name`, `description`, `version`, optional `main`, `userConfig`) + `register.js` / `.mjs` / `.ts` / `.mts` | +| Claude Code | `.claude-plugin/plugin.json` + `hooks/hooks.json` (`{ "modules": ["./register.js"] }`) | + +`userConfig` (`{ key: { type, default, description } }`) values arrive as `register`'s +`options`. TypeScript entries need Node ≥ 22.13 (types are stripped); otherwise use `.js`. + +| Scope | Directory | Loads when | +| --- | --- | --- | +| built-in | shipped with QodeX (`qodex mod path`) | by its manifest's `defaultEnabled`, until you enable/disable it | +| user | `~/.qodex/mods//` | enabled (the default) | +| project | `/.qodex/mods//` | only after `qodex mod trust ` / `/mods trust ` — and again after its entry file changes | +| session | `--mod-dir

` (repeatable), `QODEX_MOD_DIRS` | always, with hot reload | + +Enabled / disabled / trusted state and per-mod config live in `~/.qodex/mods.json`. Mods +load in a fixed order (scope, then name) with the built-ins last, so your mod can wrap a +built-in one. + +## Hooks + +```js +on(event, [matcher], async ($, e, next) => { … }) +``` + +A hook is middleware. `return next(e)` passes the event on (later mods, then QodeX's own +step); `next({ ...e, field })` passes a changed copy; returning an object answers the event +without the rest of the chain. `e` is deeply frozen. A matcher filters on payload fields by +equality or list membership — `{ tool: 'bash' }`, `{ component: ['Pane', 'AbovePrompt'] }`; +`'*'` hooks every event. `next.signal` aborts when the event is abandoned (Esc, `/stop`), +`next.origin` says who fired it, `next.budget` is the hook's time limit. + +A hook that throws or runs over its own 10 s is **skipped** — the chain continues with the +event as it was — and logged; `.catch(handler)` on the registration runs instead (1 s). One +bad mod never breaks QodeX. + +| Event | `e` | A hook may return | +| --- | --- | --- | +| `session.start` | sessionId, cwd, surface | — (once per mod before the first prompt, and after its reload) | +| `session.end` | sessionId, reason | — | +| `session.compact` | sessionId, tokens | `{ skip: reason }` | +| `prompt.submit` | text, context, source | `next({ ...e, text })`, `next({ ...e, context })`, `{ drop: reason }` | +| `prompt.section` | name, text | `{ text }`, `{ text: null }` to omit it | +| `tool.call` | tool, args, callId, cwd | `{ deny: reason }`, `{ result, isError? }`, `next({ ...e, args })` | +| `tool.check` | tool, operation, decision | `{ decision: 'allow' \| 'ask' \| 'deny' }` (see [Security](#security-and-trust)) | +| `tool.result` | tool, args, callId, result, isError, durationMs | `{ result }` | +| `tool.describe` | tool, description | `{ description }` | +| `turn.start` | turn, prompt | — | +| `turn.step` | turn, step, model | `next({ ...e, model })` | +| `turn.complete` | turn, answer, aborted, toolCalls, usage | `{ text }` — a dim line under the answer | +| `agent.spawn` | role, task, model | `{ deny }`, `{ model }` | +| `command.run` | command, args | `{ text }`, `{}` | +| `ui.render` | component, requestId, surface, props, viewport | an element tree, or `next(e)` | +| `ui.press` | key, requestId | — | + +## The `$` mods API + +| Namespace | Methods | +| --- | --- | +| `$.plugin` | `name`, `root` | +| `$.command` | `register({ name, description, argumentHint?, immediate? })` (built-in names refused; `immediate` runs during a turn), `list()` | +| `$.tool` | `register({ name, description, inputSchema, readOnly? })` → the model sees `mod____`; answer it in a `tool.call` hook. `list()` | +| `$.model` | `complete({ prompt, system?, model: 'fast' \| 'default' \| id, maxTokens? = 1024, timeoutMs? })` → `{ isAnswered: true, text }` or `{ isAnswered: false, reason }`; never rejects on API errors | +| `$.prompt` | `submit({ text, asUser? })` — a turn once the session is idle; the model is told which mod sent it unless `asUser` | +| `$.turn` | `abort(reason?)` | +| `$.session` | `id()`, `cwd()`, `model()`, `messages()` (newest 4,096), `usage()` (context tokens/window/percent and by category, cost, budget limits) | +| `$.ui` | `resolve(e)`, `invalidate()`, `open({ id, title?, rows?, focus?, closeOnEscape? })`, `close({ id })`, `status(text \| null)`, `toast(text, { timeoutMs? })`, `log(text)`, `notice(text)` | +| `$.fs` | `read`, `write`, `exists`, `list` — relative to the session cwd, 4 MiB per file | +| `$.process` | `run(argv, { cwd?, timeoutMs?, stdin? })` — an argument list, no shell; 30 s default, 10 min max | +| `$.http` | `fetch(url, { method?, headers?, body?, timeoutMs? })` | +| `$.store` | `get`, `set`, `delete`, `keys` — JSON kept between sessions in `~/.qodex/mods-store/.json` (4 MiB, atomic writes) | +| `$.clock` | `now`, `sleep`, `after`, `every` — timers are cancelled when the mod reloads or unloads | +| `$.env` | `get(name)` | +| `$.settings` | `read()` — QodeX's effective config, secrets redacted | + +## Drawing in the terminal + +`ui.render` runs for each **render site**; filter on `{ component }`: + +| Site | Where | `e.props` | +| --- | --- | --- | +| `AbovePrompt` | the band directly above the prompt box; every mod's tree is stacked, in load order | isWorking, maxRows, bodyColumns | +| `Pane` | a framed region above the prompt, opened with `$.ui.open({ id })`; `e.requestId` is that id. Several panes show as tabs | title, isFocused, bodyColumns, placement (`inline`) | +| `Spinner` | the "crafting…" word while a turn runs: `next({ ...e, props: { ...e.props, suffix } })` adds text after it, a tree replaces it (`await next(e)` inside the tree keeps QodeX's word) | word, message, suffix, mode | + +Elements come from `const { Box, Text, Button, Link, Markdown, Bar } = $.ui.resolve(e)`: + +| Element | Props | +| --- | --- | +| `Box` | `flexDirection`, `gap` / `columnGap` / `rowGap`, `padding*`, `margin*`, `width`, `height`, `borderStyle`, `borderColor`, `justifyContent`, `alignItems`, `flexGrow`… | +| `Text` | `color`, `backgroundColor`, `bold`, `italic`, `underline`, `strikethrough`, `dimColor`, `inverse`, `wrap`; children are strings, `Text` or `Link` | +| `Button` | `key`, `label`, `onPress`, `hotkey` (one digit or lowercase letter), `plain` (`1: One` instead of `[ One ]`), `dimColor`, `autoFocus` | +| `Link` | `href`, `label` | +| `Markdown` | `text` (≤ 10,000 chars), `dimColor` | +| `Bar` | `segments: [{ label, value, color }]`, `total`, `width`, `showLegend` — a stacked bar with a legend (QodeX addition) | + +Colors: named terminal colors, `#rgb` / `#rrggbb`, `rgb(r,g,b)`, `ansi256(n)`, or a theme key +(`success`, `error`, `warning`, `info`, `accent`, `subtle`…). Every tree is validated before +it is drawn: an unknown element or prop, a misplaced child or an oversized tree refuses +that mod's tree, nothing is drawn for it, and the transcript shows +`● : ui.render () refused: ` once. Terminal control characters (escape +sequences, carriage returns) are removed from every string a mod draws. + +A drawing is a snapshot: keep state in module variables (or `$.store`) and call +`$.ui.invalidate()` after changing it. Redraws are throttled to 10 a second and repaint only +when the drawing changed. + +**Keyboard.** `Ctrl+X` then `Tab` moves the keyboard to the first pane, the next pane, the +band (when it has buttons) and back to the prompt. While a pane or the band has it: `Tab` / +arrows move between buttons, `Enter` or a button's hotkey presses it, `Esc` gives the +keyboard back (and closes a `closeOnEscape` pane), `Ctrl+X X` closes the pane. Other keys +never reach the prompt meanwhile; `Ctrl+C`, `Shift+Tab` and `Ctrl+B` keep working. +`$.ui.open({ id, focus: true })` takes the keyboard only while the prompt is empty. + +**Lines outside the drawing.** `$.ui.status(text)` — one line per mod under the prompt, +`⚠ : text`, until replaced or cleared with `null`. `$.ui.toast(text)` — a short notice +at the top of the prompt area for 4 s. `$.ui.log(text)` — a dim `● : …` transcript line. +`$.ui.notice(text)` — a highlighted `💡 : …` transcript line. The model never reads +status, toast, log or notice lines. Without a terminal (headless `--print`), log and notice +go to stderr and drawing is skipped. + +## Limits + +| Limit | Value | +| --- | --- | +| A hook's own time per event (time inside `next` and `$` calls excluded, except `clock.sleep`) | 10 s | +| A `.catch` handler | 1 s | +| All `session.end` hooks together | 1.5 s | +| `$.process.run` | 30 s default, 10 min max | +| `$.model.complete` `maxTokens` | 1024 by default | +| `$.fs.read` / `write`, `$.store` | 4 MiB | +| One `Text` string child, `Markdown` text | 10,000 characters | +| A tree | 2,000 elements, 32 levels | +| Redraws | 10 a second | +| Toasts | 4 s unless `timeoutMs` (0.5–60 s); the newest 3 show | +| Command, tool and pane names | letters, digits, `_`, `-`; up to 64 | + +## Security and trust + +- **Mods are code that runs with your permissions** — like a shell script you install. + Install only mods you trust; read a mod before enabling it. +- Writes into `~/.qodex/mods/**`, `~/.qodex/mods.json` and `/.qodex/**` are agent + instruction-file writes: QodeX **asks you in every approval mode**, auto included, so a + prompt-injected page cannot install a mod. +- **Project mods never load until you trust them**; trust records the directory and a hash of + the entry, and a changed entry needs trusting again. +- `tool.check` can tighten a decision freely, but can never turn into *allow*: a hard deny + rule or deny pattern, a Sentinel-critical action (purchase, payment, credential, send, + integrity), an instruction-file write, or an auto-mode "still asks" decision. Those always + reach you. +- `$.prompt.submit` can queue a turn but never a slash command — a mod cannot type `/auto` + for you. A mod never answers a permission prompt. +- `$.settings.read()` redacts secrets. Status, toast, log and notice lines are never sent to + the model. + +## Built-in mods + +| Mod | Default | What it does | +| --- | --- | --- | +| `context-bar` | on (bar hidden) | `/context-bar [on\|off]` toggles a stacked bar above the prompt: one color per kind of context (system, tools, rules, memory, messages, tool results, free), a legend and `% of `. The choice is kept in its store. | +| `you-should-know` | off — `/mods enable you-should-know` | After each turn (and at most every 3 minutes during a long one) a fast model reads the recent transcript (last request, recent entries, tool errors, edited files and a `git diff --stat` summary) and answers: did the user or the agent miss something — an ignored failing test or command, an unverified claim, the wrong file edited, a secret printed, an instruction not followed, a TODO left? `NONE`, or one `💡` line. Never starts a turn, 120 output tokens per look, repeats dropped, silent after `/stop`. | +| `sample-hello` | off (docs only) | `/hello-tabs` opens a pane with two tabs and a counter kept in `$.store` — Claude Code's hello-tabs example, unchanged. | + +Their source (`qodex mod path`) uses the public API only — copy them. + +## Commands + +| Command | | +| --- | --- | +| `/mod new ` | QodeX writes a mod for you | +| `/mods` · `/mods enable\|disable\|trust ` | list mods, turn them on or off, trust a project mod | +| `/reload-mods` | reload every mod | +| `qodex mod list` · `new ` · `validate ` · `test ` | list, scaffold, check (events, commands, tools and `$` calls used; errors), run `/*.test.(js\|mjs\|ts)` against a fake `$` | +| `qodex mod enable\|disable\|trust\|untrust ` · `qodex mod path` | state, and where mods live | +| `--mod-dir ` | load a mod directory for this session (repeatable, hot reload) | + +## Claude Code compatibility + +Runs unchanged: `register(on, options)` from `hooks/hooks.json` modules, middleware hooks +and matchers, `.catch`, `next.signal` / `origin` / `budget`, the events and `$` methods in +the tables above, `Box` / `Text` / `Button` / `Link` / `Markdown`, panes with `focus` and +`closeOnEscape`, hotkeys and `autoFocus`, `$.store`, the limits. + +Differences: + +- **Render sites**: `AbovePrompt`, `Pane` and `Spinner` only. Panes are always the framed + region above the prompt (no sidebar dock, no resize keys, no scroll keys, no mouse). +- **The band stacks** every mod's tree; a tree does not hide the trees of later mods, so + `await next(e)` inside your band tree is not needed (it is harmless). +- **Elements**: no `Input`, `Select`, `Code`, `Svg`, `Client`, `Raster` or `Image` — a tree + using one is refused with a readable reason. `Bar` is QodeX's own. +- **A refused tree draws nothing** for that mod (Claude Code draws its own version of the site). +- **Not available**: `$.state` and its helpers (use module variables + `$.store`), `$.mcp`, + `$.audio`, `$.config`, `$.agent`, `$.telemetry`, `$.ui.ask` / `copy` / `blit` / `focus` / + `scroll` / `panes`, `$.model.fork` / `classify`, `$.process.spawn`; events `classic.*`, + `prompt.compose` / `fill` / `suggest` / `edit` / `context` / `attachment`, `session.receive` / + `send` / `append` / `measure`, `agent.offer`, `ui.input` / `select` / `focus` / `scroll` / + `close` / `message`, `plugin.register`, `engine.create`, `telemetry.*`. +- **Additions**: the `mod.json` layout, `Bar`, `$.ui.notice`, `$.session.usage()` with context + by category, cost and budget limits, `turn.complete` usage, trust-gated project mods. +- **Tools**: `qodex mod validate` / `test` play the part of `claude plugin validate` / `test`; + the store lives in `~/.qodex/mods-store/`. + +## خلاصه فارسی + +**مود (mod)** یک ماژول کوچک جاوااسکریپت/تایپ‌اسکریپت است که به رویدادهای خودِ QodeX وصل می‌شود: می‌تواند فراخوانی ابزار را نگه دارد یا تغییر دهد، پرامپت را بازنویسی کند، بالای کادر پرامپت یا زیر آن چیزی نشان دهد (نوار، پنل، خط وضعیت، اعلان کوتاه)، فرمان اسلش یا ابزار جدید اضافه کند، از یک مدل سریع سؤال کند یا کاری را زمان‌بندی کند. ساختار آن با مودهای Claude Code یکی است و مودهای ساده‌ی Claude Code بدون تغییر اجرا می‌شوند. + +- **ساختن مود**: `/mod new <توضیح>` — QodeX مود را در `~/.qodex/mods/<نام>/` می‌نویسد (نوشتن در این پوشه در **همهٔ** حالت‌ها، حتی auto، از شما اجازه می‌گیرد و همین تأیید یعنی رضایت شما به نصب کد)، با `qodex mod validate` بررسی و با `/reload-mods` بارگذاری می‌کند. +- **محل مودها**: کاربر `~/.qodex/mods`، پروژه `.qodex/mods` (فقط پس از `qodex mod trust <نام>`؛ با تغییر فایل دوباره اعتماد لازم است)، و پوشه‌ی موقت با `--mod-dir`. +- **صفحه**: نوار بالای پرامپت (همهٔ مودها روی هم)، پنل قاب‌دار بالای پرامپت (چند پنل = زبانه)، خط وضعیت زیر پرامپت، اعلان ۴ ثانیه‌ای، و خطوط `●` و `💡` در تاریخچه که مدل هرگز نمی‌خواند. `Ctrl+X` سپس `Tab` کیبورد را به پنل می‌دهد، کلیدهای میان‌بر دکمه‌ها را می‌زنند و `Esc` کیبورد را برمی‌گرداند. +- **امنیت**: مود کدی است با دسترسی شما — فقط مود مورد اعتماد نصب کنید. مود هرگز نمی‌تواند ممنوعیت قطعی، اقدام حساس Sentinel (خرید، پرداخت، رمز، ارسال)، نوشتن در فایل‌های دستورالعمل یا پرسش‌های حالت auto را به «مجاز» تبدیل کند و نمی‌تواند به‌جای شما فرمان اسلش اجرا کند. +- **مودهای داخلی**: `context-bar` (با `/context-bar` نوار مصرف پنجرهٔ کانتکست به تفکیک دسته)، `you-should-know` (خاموش؛ بعد از هر نوبت یک مدل سریع نکته‌ی جاافتاده — تست شکست‌خورده، ادعای بررسی‌نشده، TODO — را در یک خط `💡` می‌گوید)، و `sample-hello` (نمونه‌ی آموزشی). diff --git a/docs/VAULT_AND_CAPTCHA.md b/docs/VAULT_AND_CAPTCHA.md new file mode 100644 index 0000000..5e365c2 --- /dev/null +++ b/docs/VAULT_AND_CAPTCHA.md @@ -0,0 +1,133 @@ +# Password vault and CAPTCHA hand-off + +QodeX keeps your site logins in an encrypted vault the agent can **use** but never **read**, and it +hands CAPTCHAs / bot checks to **you** — it never solves them. See also [AGENT_PLATFORM.md](AGENT_PLATFORM.md). + +## The vault key, editing and importing + +- **Where the key lives:** `qodex vault key status` shows the backend; `qodex vault key migrate ` + moves the vault key into the macOS Keychain, the Secret Service (GNOME Keyring / KWallet via `secret-tool`) or Windows DPAPI + (the secret is always passed on stdin, never on a command line). The choice is recorded, so a missing key file is never + mistaken for a fresh install. The vault and the mail account store share the same key. +- **Edit / rotate:** `qodex vault edit [--origin … | --add-origin … | --login-url … | --rename …]`, `qodex vault rotate [--totp | --undo]` (keeps the + other fields and the previous password for an undo). +- **Import:** `qodex vault import [--format …|auto] [--dry-run] [--on-conflict skip|replace|rename]` reads a + password-manager / browser export (only counts are printed). Delete the plaintext export afterwards; the agent is not allowed + to read such files. + +### Logging in with the vault + +- `browser_login {secret, url?, submit?}` signs in with a vault entry in one step. It opens the entry's login page (or uses the open login form), fills the username and password (including username-first forms where the password page comes second) and the current 2FA code if the entry has a seed. It submits with the form's own button, but only after Sentinel checks the button's label, so a "Sign in and pay" button is refused. It reports where it landed. If a login fails, it does not retry: that entry is held for 15 minutes unless it is changed. A page that redirects to another site is refused, and CAPTCHAs are left for a human. +- `vault_generate_and_fill {ref?, confirm_ref?, name?, username?, length?}` is for sign-up and change-password forms. It creates a strong random password and saves it to the vault before typing it (a new entry for the site, or a rotation of `name`), then fills the new-password and confirm fields. It respects the field's maxlength. If typing fails, the vault change is undone. +- The agent never sees the values. Results, errors, progress events, the action recorder and the approval prompts show `***` or nothing. Both tools are classed as credential actions with high risk, so Sentinel asks in manual mode. +- Requests like "log me in with my saved password", "the 2FA code from my authenticator app", «رمز عبورم», «گاوصندوق» or «کد دو مرحله‌ای» bring in the vault tools without naming a site. A plain coding task that mentions "password" does not. +- Recorded workflows replay a `browser_login` as steps on the fields' autocomplete tokens (username / current-password / one-time-code). The steps read their values from the vault entry. + +### Logins typed by you, never by the chat (vault entry + save-login) +- When the agent needs a login it calls `vault_request_login`. You type it into QodeX's masked terminal prompt or the control center's secure form. The value goes straight into the encrypted vault; the agent, chat, logs and Telegram never see it. +- The control-center form works only on this computer (localhost) or through the https tunnel link. Over a tunnel the page encrypts the form itself (ECDH P-256 + AES-256-GCM) before sending it. Plain http on the local network is refused. Only the full control-center link can enter or manage secrets. +- Vault panel (control center): see saved logins (usernames masked, passwords never shown), add one, change a password or 2FA key, edit sites or the login URL, or delete with confirmation. +- Save-login: if you log in to a site yourself during a takeover, QodeX asks "Save the login for (user ab***)?" in the terminal and the control center. Yes saves or updates the vault entry; the question never contains the password. The agent's own typing never triggers it, and a page that still shows the login form (wrong password) waits until you hand back. +- Not included yet: a master passphrase with session unlock (follow-up). + +### ورودهایی که خودتان تایپ می‌کنید، نه چت (ورود به گاوصندوق + ذخیرهٔ ورود) +- وقتی عامل به ورود نیاز دارد `vault_request_login` را صدا می‌زند؛ شما آن را در اعلان پنهان ترمینال QodeX یا فرم امن مرکز کنترل تایپ می‌کنید. مقدار مستقیم به گاوصندوق رمزنگاری‌شده می‌رود؛ عامل، چت، لاگ‌ها و تلگرام هرگز آن را نمی‌بینند. +- فرم مرکز کنترل فقط روی همین رایانه (localhost) یا از لینک https تونل کار می‌کند. روی تونل، خود صفحه فرم را پیش از ارسال رمزنگاری می‌کند. http سادهٔ شبکهٔ محلی رد می‌شود. فقط لینک کامل مرکز کنترل اجازهٔ ورود یا مدیریت رمزها را دارد. +- پنل گاوصندوق: فهرست ورودها (نام کاربری پوشیده، رمز هرگز نمایش داده نمی‌شود)، افزودن، تغییر رمز یا کلید دومرحله‌ای، ویرایش سایت‌ها و آدرس صفحهٔ ورود، و حذف با تأیید. +- ذخیرهٔ ورود: اگر هنگام گرفتن کنترل خودتان وارد سایتی شوید، QodeX در ترمینال و مرکز کنترل می‌پرسد «ورود <سایت> (کاربر ab***) ذخیره شود؟». بله ورودی گاوصندوق را می‌سازد یا به‌روز می‌کند و رمز هرگز در پرسش نیست. تایپ خود عامل هرگز این پرسش را ایجاد نمی‌کند، و اگر صفحه هنوز فرم ورود را نشان دهد (رمز اشتباه) تا پس دادن کنترل صبر می‌کند. +- هنوز موجود نیست: گذرواژهٔ اصلی با باز کردن در هر نشست (کار بعدی). + +### CAPTCHA / bot checks: hand-off, never solving (browser) +QodeX never solves CAPTCHAs. It uses no solver services, no vision or audio solving, no clicking, typing or dragging into a challenge widget, no synthesized "human" input and no fingerprint spoofing. `browser.stealth` is now **off** by default. +- **Detection** covers: + - reCAPTCHA (a visible checkbox or challenge only; the v3 badge is ignored) and hCaptcha + - Cloudflare Turnstile and the "Just a moment…" page + - Akamai, PerimeterX "Press & Hold", DataDome and AWS WAF + - Arkose, GeeTest, Kasada, DDoS-Guard, Sucuri and Imperva + - plain image CAPTCHAs +- **Self-clearing checks are waited out** for up to `browser.challengeAutoWaitSec` (default 20 s), with no model calls. +- **Anything else shows up as `[CHALLENGE]`.** The agent then calls `browser_request_human`: + - QodeX takes over the browser so the agent waits. + - It asks you on every channel (terminal, control center live view, Telegram) and you choose `done` or `cancel`. + - It continues by itself as soon as the check is gone; you don't need to answer. + - If nobody solves it within `browser.handoffTimeoutSec` (default = `sentinel.remoteApprovalTimeoutSec`, 600 s), the result is `[CHALLENGE_UNSOLVED]`. The agent stops and tells you; it does not retry. +- **The agent can never act on a challenge** (`[CHALLENGE_HUMAN_ONLY]`), and recorded workflows never contain challenge steps. +- **Seeing fewer challenges, legitimately:** + - `browser.headless: auto` (the default) opens a visible window when you use the TUI on a desktop. `--print`, missions and machines without a display stay headless; `QODEX_BROWSER_HEADLESS=1` opts out. + - A configured `browser.channel: chrome` is used for the visible window. + - Agent actions on the same site are paced by `browser.hostPacingMs` (≤ 1 s). + - A page whose last two loads were bot checks is not reloaded again. +- `browser.challengeHandoff`: `auto` (default) | `report` (only report it; no hand-off) | `off` (no detection). +- New built-in skills: `sign-up` and `manage-site`. + +### کپچا و بررسی ربات: سپردن به شما، هیچ‌وقت حل‌کردن خودکار +- QodeX کپچا را هرگز خودش حل نمی‌کند: نه سرویس حل کپچا، نه تشخیص تصویر یا صدا، نه کلیک روی «من ربات نیستم» و نه جعل اثر انگشت مرورگر. stealth حالا به‌طور پیش‌فرض خاموش است. +- بررسی‌هایی که خودشان رد می‌شوند (مثل «Just a moment…» کلودفلر) تا ۲۰ ثانیه صبر می‌شوند. +- اگر کپچا به آدم نیاز داشته باشد، QodeX مرورگر را به شما می‌سپارد: از ترمینال، مرکز کنترل یا تلگرام چند ثانیه وقت می‌گذارید و حلش می‌کنید. +- QodeX به‌محض رفع کپچا خودش ادامه می‌دهد؛ لازم نیست «done» بزنید. +- اگر در زمان تعیین‌شده حل نشود، کار متوقف می‌شود و به شما خبر داده می‌شود. QodeX خودش دوباره امتحان نمی‌کند. +- برای اینکه کمتر کپچا ببینید: + - در TUI روی دسکتاپ یک مرورگر واقعی و قابل‌دیدن باز می‌شود. + - Chrome خودتان (`browser.channel: chrome`) به کار می‌رود. + - بین درخواست‌ها به یک سایت فاصله گذاشته می‌شود. + +### Hand-offs: CAPTCHAs and bot checks +QodeX never solves a CAPTCHA. When a check needs a person, QodeX hands the browser to you and continues by itself as soon as the check is gone. +- **Telegram**: you get a card with a screenshot cropped to the check and two buttons, ✅ Done and ✖️ Can't solve it. It also has a 🖐 Open live view button: a one-tap link that opens only this check's live view (no approvals, missions, steering, stop or vault). The link expires after `browser.handoffLinkTtlSec` (default 10 min) or when the hand-off ends. QodeX stores only a hash of the link. Telegram refuses links to this computer or to a local network in buttons; the card then comes without the button. On a LAN control center it names the Wi-Fi address instead, which opens on a phone already logged in with the private `?k=` link. For a one-tap link from anywhere, start the control center with `/control --tunnel`. Or set `control.handoffTunnel: true` so a hand-off opens the control center and a public quick tunnel by itself (off by default). When the check clears, the card changes to "✓ Challenge cleared, continuing". +- **Control center**: `?handoff=` (or the link) opens hand-off mode: the live view comes first on phones, zoomed to the check, with Done / Can't buttons. Your own press-and-hold and drag are relayed as you make them; a hold lasts at most 15 s and is always released. Pinch to zoom; use Keyboard for text CAPTCHAs. +- **Terminal**: the prompt says "Solve it in the browser window or the control center — QodeX continues automatically" and shows the local control-center URL. Press d for done, c for can't, Esc stops the task. +- **Detached missions**: the hand-off reaches Telegram as a text card (Done / Can't) through the mission queue, with no screenshot or link, because the worker's browser runs in another process. + +### واگذاری‌ها: کپچا و بررسی‌های ضدربات +QodeX هرگز کپچا را حل نمی‌کند. وقتی یک بررسی به انسان نیاز دارد، مرورگر را به شما می‌سپارد و به محض برطرف شدن آن، خودش ادامه می‌دهد. +- **تلگرام**: یک کارت با تصویرِ برش‌خورده از همان بررسی و دو دکمهٔ «✅ انجام شد» و «✖️ نمی‌توانم حلش کنم» می‌گیرید. دکمهٔ «🖐 باز کردن نمای زنده» هم دارد: یک لینک تک‌لمسی که فقط نمای زندهٔ همین بررسی را باز می‌کند (نه تأییدها، نه مأموریت‌ها، نه هدایت، نه توقف، نه گاوصندوق). این لینک پس از `browser.handoffLinkTtlSec` (پیش‌فرض ۱۰ دقیقه) یا با پایان واگذاری از کار می‌افتد و QodeX فقط هشِ آن را نگه می‌دارد. تلگرام لینکِ همین کامپیوتر یا شبکهٔ محلی را در دکمه نمی‌پذیرد؛ آن‌وقت کارت بدون دکمه می‌آید. اگر مرکز کنترل روی شبکهٔ محلی باشد، نشانیِ Wi-Fi را می‌نویسد که در گوشیِ واردشده با لینک خصوصی `?k=` باز می‌شود. برای لینک تک‌لمسی از هر جا، مرکز کنترل را با `/control --tunnel` اجرا کنید، یا `control.handoffTunnel: true` را تنظیم کنید تا واگذاری خودش مرکز کنترل و یک تونل عمومی موقت را باز کند (پیش‌فرض خاموش). وقتی بررسی برطرف شود، کارت به «✓ بررسی برطرف شد، ادامه می‌دهیم» تغییر می‌کند. +- **مرکز کنترل**: `?handoff=` (یا همان لینک) حالت واگذاری را باز می‌کند: در گوشی نمای زنده اول می‌آید، روی بررسی بزرگ‌نمایی شده و دکمه‌های «انجام شد» و «نمی‌توانم» دارد. نگه‌داشتن و کشیدنِ خودِ شما همان‌طور که انجام می‌دهید منتقل می‌شود؛ هر نگه‌داشتن حداکثر ۱۵ ثانیه است و همیشه رها می‌شود. با دو انگشت بزرگ‌نمایی کنید؛ برای کپچای متنی دکمهٔ «صفحه‌کلید» را بزنید. +- **ترمینال**: پیام می‌گوید «آن را در پنجرهٔ مرورگر یا مرکز کنترل حل کنید — QodeX خودش ادامه می‌دهد» و نشانیِ مرکز کنترل محلی را نشان می‌دهد. d یعنی انجام شد، c یعنی نمی‌توانم، و Esc کار را متوقف می‌کند. +- **مأموریت‌های جدا**: واگذاری از طریق صف مأموریت به‌صورت کارت متنی (انجام شد / نمی‌توانم) به تلگرام می‌رسد، بدون تصویر و لینک، چون مرورگرِ worker در پردازش دیگری اجرا می‌شود. + +## Web Bot Auth — an honest agent identity (optional) + +QodeX never hides that it is automated. The opposite option is **Web Bot Auth**: QodeX +signs its own requests with an Ed25519 key so a site can *recognise* QodeX — "this is the +agent, acting for its user" — and choose to let it through. It earns fewer bot challenges +by being identifiable, not by evading detection. Off by default. + +It implements HTTP Message Signatures (RFC 9421) with the `web-bot-auth` tag (the +Cloudflare / IETF draft). Each signed request carries `Signature-Agent` (the URL where +you publish the public key), `Signature-Input` and `Signature`, covering the target +`@authority` and that directory URL. + +Set it up: +1. `qodex browser bot-auth --init` creates the key at `~/.qodex/browser/bot-auth/ed25519.pem` + (0600). The private key never leaves the machine; Sentinel keeps the agent out of that + folder, so QodeX itself can never read, copy or change the key. +2. In `~/.qodex/config.yaml`: + ```yaml + browser: + botAuth: + enabled: true + directoryUrl: https://your-domain/.well-known/http-message-signatures-directory + ``` +3. `qodex browser bot-auth --directory` prints the public key as a JWK Set — host it at + that URL. A site (or Cloudflare) fetches it to verify the signature. To get fewer + challenges on Cloudflare you also register the agent in its verified-bots programme; + QodeX provides the signature, you do the registration. + +What it is and is not: +- It signs only same-site `document`, `xhr` and `fetch` requests on public hosts. Images, + fonts and third-party subresources are not signed. Loopback / LAN pages (dev servers) + are never signed, and the user's own Chrome (`cdpUrl`) is never touched. +- `QODEX_BROWSER_BOT_AUTH=1|0` forces it on / off; `browser_status` and + `qodex browser status` show it. +- It does **not** spoof a fingerprint, hide `navigator.webdriver`, or forge human input. + A site is free to ignore the signature. Signing requests reduces HTTP caching a little + (lean mode still saves image/font/media bandwidth). + +**خلاصهٔ فارسی.** «Web Bot Auth» هویت صادقانهٔ ایجنت است، نه پنهان‌کاری: QodeX درخواست‌های +خودش را با یک کلید Ed25519 امضا می‌کند تا سایت بفهمد «این QodeX است که از طرف کاربرش کار +می‌کند» و اجازهٔ عبور بدهد. پیش‌فرض خاموش است. با `qodex browser bot-auth --init` کلید ساخته +می‌شود (کلید خصوصی هرگز از دستگاه خارج نمی‌شود و Sentinel ایجنت را از آن پوشه بیرون نگه +می‌دارد)، بعد در config مقدار `browser.botAuth.enabled: true` و `directoryUrl` را بگذارید و +خروجی `qodex browser bot-auth --directory` را روی آن نشانی منتشر کنید. فقط درخواست‌های +هم‌سایتِ صفحه روی میزبان‌های عمومی امضا می‌شوند؛ localhost و Chrome خودتان دست‌نخورده می‌مانند. +این قابلیت اثرانگشت مرورگر را جعل نمی‌کند و رفتار انسانی نمی‌سازد. diff --git a/examples/skills/build-eval/SKILL.md b/examples/skills/build-eval/SKILL.md new file mode 100644 index 0000000..4db37d3 --- /dev/null +++ b/examples/skills/build-eval/SKILL.md @@ -0,0 +1,75 @@ +--- +name: build-eval +description: Build an eval for an LLM app or agent setup — interview, sample real cases, pick the cheapest grader that measures the right thing, write evals// (cases, grader, run script), run a baseline after the user signs off. Load before changing a prompt, model, skill or tool description you want to measure. +version: 1.0.0 +author: QodeX +triggers: + - build an eval + - eval set + - evals + - measure my prompt + - did my change help + - ارزیابی +slash-aliases: + - build-eval +allowed-tools: + - ask_user + - read_file + - write_file + - edit_text + - ls + - glob + - grep + - shell + - git_log + - git_diff + - todo_write + - background_job_start + - background_job_status + - background_job_log +--- +# Build an eval + +An eval is three things: inputs the user agrees are the cases that matter, a way to run the +system on each one, and a grade they would have given themselves. Fit it into the repo's own +language and layout; do not bring a framework. + +## 1. Interview (ask_user, one question at a time, your recommendation first) +- What is under test: their app (a prompt + model call, an agent, a pipeline) or this QodeX + setup (QODEX.md, skills, tool descriptions, model, effort)? +- What change is coming that this eval must judge? What would make them roll it back? +- Name: short, kebab-case — everything goes in `evals//`. + +## 2. Sample real cases +Pull inputs from what already happened before inventing any: logs and traces, support tickets +or issues, failing tests, `git_log` for bug fixes, fixtures in the code. Aim for 20–50 at first. +Cover the common path, the known failures, and the cases that must NOT trigger (negatives). +Strip secrets and personal data. Show the list and get an explicit "yes, these are the cases". + +## 3. Pick the cheapest grader that measures the right thing +Try in this order and stop at the first that fits the output's shape: +1. Exact match or a label from a closed set. +2. Regex / contains / JSON-schema check. +3. Code check: the tests pass, the file compiles, the end state of a scratch workspace is right + (for agents, grade the end state, not the transcript). +4. LLM judge — last, for open-ended text only: a short rubric, a reason before the score, and a + cheap fast model (`haiku`) unless the user picks another. +Grade five pilot cases, show outputs next to grades, and ask "would you have graded any of +these differently?" Iterate until the answer is no. With positives and negatives, report +precision and recall, not only accuracy. + +## 4. Write `evals//` +- `cases.jsonl` — one object per line: `{"id","input","expected","split","tags"}`; `split` is + `train` or `holdout` (about 70/30, stratified by tag) so `hillclimb` can use it as is. +- the grader (`grade.mjs` / `grade.py`, matching the repo) — pure: (case, output) → `{pass, score, why}`. +- the run script (`run.mjs` / `run.py` / `run.sh`) — runs every case, writes + `results/