diff --git a/README.md b/README.md index 5be148d..c59bf84 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,7 @@ Install and update also rebuild internally; the explicit build above lets you ch - Bash 4.3 or newer, with standard utilities such as `awk`, `sed`, and `sha256sum`. - Python 3.11 or newer for configuration validation and task-state hooks/helpers (`python` for PowerShell scripts, `python3` for Bash scripts). - `jq` for Claude's Bash status line; without it, that status line produces no output. -- Node.js 22 or newer and `npm` when local QMD search is enabled. -- Node.js 22 or newer and `npm` when MCPorter is selected. +- Node.js 22 or newer and `npm` when local QMD search or MCPorter is selected. Core Bash setup scripts do not require PowerShell. The credential commands use Windows Credential Manager and require PowerShell, including when invoked through their Bash wrappers. The PowerShell scripts remain compatible with @@ -128,6 +127,11 @@ shared definitions -> client adapters -> generated packages -> user installation | [`scripts/`](docs/scripts.md) | Build, installation, update, diagnosis, and validation scripts. | | `docs/` | Focused documentation about the configuration design. | +Client settings start in `adapters/codex/config/config.toml` and +`adapters/claude/config/settings.json`. Shared Markdown and metadata define behavior; +adapters supply client-specific formats and placeholders resolved during build or installation. +Generated output is not a source to edit. + The build creates: ```text @@ -142,16 +146,13 @@ generated/ | Document | Contents | | --- | --- | -| [Architecture](docs/architecture.md) | Shared sources, adapters, generated packages, and installation. | | [Scripts](docs/scripts.md) | Commands, checks, tests, and internal script layout. | -| [Configuration](docs/configuration.md) | Client settings, permission defaults, status displays, and verification. | +| [Configuration](docs/configuration.md) | Client settings, permissions, status displays, local QMD search, and verification. | | [Extending the configuration](docs/extending-configuration.md) | Add shared rules, skills, and agents. | | [Plugins](docs/plugins.md) | Plugin sources, selection, installation, updates, and removal. | | [Hooks](docs/hooks.md) | Registered events, session-state helpers, notifications, and optional utilities. | | [Agents](docs/agents.md) | Agent roles and when delegation is useful. | | [Skills](docs/skills.md) | Skill categories and conditional rule loading. | -| [Codex adapter](adapters/codex/README.md) | Codex-specific configuration files. | -| [Claude Code adapter](adapters/claude/README.md) | Claude-specific configuration files. | | [Hook package](shared/hooks/README.md) | Overview shipped with the hook scripts. | | [Repository instructions](AI-Instructions.md) | Rules for maintaining this repository. | @@ -233,9 +234,9 @@ Selecting Codex also installs shared skills to `.agents/skills`. An interactive Codex skills; unchecked extensions are skipped on installation. Normal install and update ask whether to enable Flashbang, apply the custom status line, and enable local QMD search. Choices are saved for Quickupdate. The shared skill catalog includes development skills and focused writing, image, site structure, psychology, and -conversion skills. All retained skills are included in both generated clients. +conversion skills. All retained skills are included in both generated clients; installation includes `semantic-search` only when local QMD search is enabled. The status line defaults to enabled to preserve existing behavior. Disabling it removes the custom client setting and, -for Claude, the setup-owned status line script. Disabling local QMD search on update removes only its setup-owned package, models, and repository collections. +for Claude, the setup-owned status line script. Disabling local QMD search removes its setup-owned package, models, and repository collections once no client still uses it. See [Local QMD search](docs/configuration.md#local-qmd-search) for storage and removal details. Dry runs preview changes without updating extensions or retrieval. See [Plugins](docs/plugins.md) for client-specific behavior. ## Update Script @@ -288,8 +289,8 @@ touched. Codex skill backups are kept under `.agents/.ai-config-skill-backups/`. deleted once it is fully empty; backups already on disk are always kept. Extensions and skills recorded in the ledger are removed the same way `update` removes a deselected extension: pre-existing or manually installed ones outside the ledger are left alone, and a skill file modified since it was -installed is kept with a warning. An enabled local QMD search setup is disabled and its setup-owned runtime and -index removed for the selected client(s). The saved Quickupdate selection (`~/.my-ai-configuration/selection.json`) +installed is kept with a warning. Local QMD search is disabled for the selected client(s). Its shared runtime, +owned models, and recorded repository collections are removed only when no client still uses it; the shared QMD database and foreign collections are retained. The saved Quickupdate selection (`~/.my-ai-configuration/selection.json`) is only removed once uninstalling leaves no client installed at all, so uninstalling just one client out of a `Both` installation keeps the saved choices for the client that remains. diff --git a/adapters/claude/README.md b/adapters/claude/README.md deleted file mode 100644 index 5edac43..0000000 --- a/adapters/claude/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Claude Code adapter - -Claude Code uses global `CLAUDE.md`, `settings.json`, skills, and agents under the user profile. This adapter supplies client metadata; semantic content remains in `shared/`. diff --git a/adapters/codex/README.md b/adapters/codex/README.md deleted file mode 100644 index a1a7684..0000000 --- a/adapters/codex/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Codex adapter - -Codex uses global `AGENTS.md`, `config.toml`, skills, and agent configuration under the user profile. This adapter supplies client metadata; semantic content remains in `shared/`. diff --git a/docs/architecture.md b/docs/architecture.md deleted file mode 100644 index 94d5e50..0000000 --- a/docs/architecture.md +++ /dev/null @@ -1,5 +0,0 @@ -# Architecture - -Shared Markdown and metadata define meaning once. Codex and Claude adapters contain only client-specific paths, filenames, and serialization details. The build script renders those inputs into `generated/`. Installation is a separate, explicit step that copies generated files into global user-level locations with backups. - -Generated output is ignored because it is reproducible build output. The source files are the reviewable record. diff --git a/docs/configuration.md b/docs/configuration.md index 7bc826a..85ea182 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,6 +1,19 @@ # Configuration -Codex receives a generated global `AGENTS.md`, agent TOML files, skills, rule files, and a `config.toml` adapter. It sets workspace sandboxing with network access for shell commands (so MCPorter calls such as Context7 work without approval), automatic approval review, `agents.enabled = true`, `agents.max_concurrent_threads_per_session = 5`, and `agents.max_depth = 1`. Claude Code receives a generated global `CLAUDE.md`, agent Markdown files, skills, and `settings.json` with `auto` permissions, explicit `Agent` and `mcporter call context7.*` shell permissions, `mcp.context7.com` as the only allowed sandbox domain where the Claude sandbox is enabled, a five-operation concurrency default, at most five concurrent subagents (`CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`), and a subagent spawn depth of one (`CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`), so subagents cannot start further subagents. Installation resolves user paths at runtime; the repository contains no machine-specific paths. +Source templates are [`adapters/codex/config/config.toml`](../adapters/codex/config/config.toml) +and [`adapters/claude/config/settings.json`](../adapters/claude/config/settings.json). +Installation targets `~/.codex` and `~/.claude`; Codex skills go to `~/.agents/skills`. +Choose the PowerShell or Bash package independently of the client. + +Codex receives a generated global `AGENTS.md`, agent TOML files, skills, rule files, and a `config.toml` adapter. +It sets workspace sandboxing with shell network access, automatic approval review, `agents.enabled = true`, +`agents.max_concurrent_threads_per_session = 5`, and `agents.max_depth = 1`. + +Claude Code receives a generated global `CLAUDE.md`, agent Markdown files, skills, and `settings.json` with +`auto` permissions and explicit `Agent` and `mcporter call context7.*` shell permissions. Where enabled, its sandbox +allows the `mcp.context7.com` domain. The adapter sets a five-operation concurrency default, at most five concurrent +subagents (`CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`), and a spawn depth of one (`CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`). +Installation resolves user paths at runtime. Active session policy can further restrict these defaults. Both clients embed `shared/rules/general.md` and the rule-loading conditions from `shared/global-instructions.md`. Rules for languages and frameworks live in their own directories, with an `index.md` entry point and focused Markdown rules under `references/`. Security has its own directory with a baseline entry point and focused rules for authentication, web, APIs, data, files, network, cryptography, and supply chains. Git, Microsoft, and cross-cutting rules remain directly under `shared/rules/`. Codex receives the full directory tree; Claude generates a skill for each rule and copies supporting references alongside the index skill. @@ -33,6 +46,78 @@ Model and context-window size are cyan, effort and cumulative tokens magenta, re Claude's status line displays `permission_mode` or `permissionMode` when Claude provides it, and otherwise shows the configured `auto` review mode. +## Local QMD search + +Install and update offer **Yes / No / Auto**, with No as the initial default. This option is separate +from the extension selector. The saved `semantic_retrieval` key keeps its name for compatibility. +Quickupdate reuses the saved choice and device; it does not rerun the benchmark. + +- **Yes:** install `@tobilu/qmd@2.8.3` if QMD is absent, copy the shared runtime scripts, configure + and download the three models, and choose GPU when detected or CPU otherwise. An existing QMD + installation is reused, not upgraded by this step. +- **Auto:** prepare the same dependencies, then benchmark GPU when available and CPU if needed. + Both thresholds must pass: median warm search latency at most 5 seconds and embedding throughput + at least 20 chunks/second. Each device has a 10-minute timeout. No passing device disables search + and triggers setup-owned resource cleanup. Auto can download models while answering the setup prompt. +- **No:** omit the search skill and its instruction line, remove the warm-up hook registration, + and disable search for the selected clients. Dry runs do not download, benchmark, or remove QMD resources. + +The models are Qwen3-Embedding-0.6B, Qwen3-Reranker-0.6B, and QMD Query Expansion 1.7B. +Exact model URIs live in [`shared/qmd/qmd-lib.mjs`](../shared/qmd/qmd-lib.mjs). +Auto thresholds can be overridden with `QMD_BENCHMARK_MAX_QUERY_SECONDS` and +`QMD_BENCHMARK_MIN_CHUNKS_PER_SECOND`. The benchmark uses a temporary database and a deterministic +100-document fixture; its measurements are not an end-to-end estimate for a user's repository. + +### Search and storage + +The `semantic-search` skill calls the installed wrapper from the current Git repository: + +```text +node "$HOME/.my-ai-configuration/qmd/qmd-search.mjs" --query "Where are temporary upload failures retried?" --top-k 5 +``` + +This command works in PowerShell and Bash. `--root` selects a repository explicitly. Results are JSON +objects with `path`, `line`, `score`, and `snippet`; repository hits use relative paths and other collections +use `qmd://` URIs. Known identifiers still use direct reads or `rg`; unknown identifiers use semantic retrieval first. + +A token-protected daemon listens on `127.0.0.1`, refreshes changed repository collections, skips git-ignored +paths, and searches the current repository together with the user's default QMD collections. Repository +collections use `repo-` followed by a 12-character path hash. A SessionStart hook warms the daemon and index +in the background. Models stay loaded until the daemon stops after 30 idle minutes, configurable with +`QMD_IDLE_MINUTES`. + +On daemon failure the wrapper tries the QMD CLI against the current repository collection only. This fallback +requires an existing index; it does not create or refresh the collection. If the wrapper fails, the skill +reports the limitation and continues with `rg`. + +| Location | Contents | +| --- | --- | +| `~/.my-ai-configuration/qmd/` | Runtime scripts, daemon state, locks, collection ownership, and `warm.log`. | +| `~/.my-ai-configuration/qmd.json` | Selected device, enabled clients, and setup ownership records. | +| `$XDG_CACHE_HOME/qmd/` (default `~/.cache/qmd/`) | Shared `index.sqlite` and model cache. | +| `$QMD_CONFIG_DIR/index.yml` | Configuration when `QMD_CONFIG_DIR` is set; otherwise `$XDG_CONFIG_HOME/qmd/index.yml`, defaulting to `~/.config/qmd/index.yml`. | + +Codex's adapter grants writable roots for `~/.my-ai-configuration/qmd` and `~/.cache/qmd`. +A custom cache location needs a matching writable root. QMD also writes its configuration when registering +collections and persisting ignore lists; the resolved configuration directory must be writable under the +active sandbox. These adapter roots do not themselves grant access to `~/.config/qmd`. + +Disabling search or uninstalling one client keeps the shared runtime while another client remains enabled. +After the last client disables it, cleanup stops the daemon, removes recorded repository collections and +setup-owned models/package, restores the previous `models:` block, and removes the runtime scripts. +It preserves foreign QMD installations, models, collections, and the shared database. Failed cleanup can leave +resources behind; inspect reported warnings rather than deleting the whole cache. Updates also migrate the +old setup-owned Python retrieval directory and QMD extension ownership records. + +### Verification and troubleshooting + +Check `~/.my-ai-configuration/qmd/warm.log` for background warm-up errors. First startup or changed repositories +can take longer than a warm query. Windows sandbox setup and child-process pipe restrictions can prevent +repository discovery or daemon startup; see [Permission defaults](#permission-defaults). + +Model-free unit tests do not verify downloads, GPU support, sandbox access, or real search quality. +See [QMD tests](scripts.md#qmd-tests) for the separate test commands and dependency setup. + ## Verification and installation The agent chooses the smallest sufficient checks based on behavior, affected callers, risk, reversibility, and uncertainty. Inspection can suffice for a small change. Full builds, broad test suites, and independent reviews are not automatic; explicit user and project requirements remain binding. diff --git a/docs/hooks.md b/docs/hooks.md index 47dfc4b..fafbb18 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -9,9 +9,11 @@ The adapters register these events: | Codex and Claude | `Stop` | Run the finish notification (`flashbang`). | | Claude | `PreCompact` | Record the compaction timestamp under the installed configuration root and point to existing workspace task state. | | Claude | `SessionStart` | Print an absolute pointer if the workspace's `.ai-session/state.json` exists. | -| Codex and Claude | SessionStart | Warm the QMD index and search daemon in the background (only while local QMD search is enabled). | +| Codex and Claude | `SessionStart` | Warm the QMD index and search daemon in the background (only while local QMD search is enabled). | -The main agent alone maintains canonical task state. Hooks never write or summarize it, print its contents, or infer completed verification. They use the hook event's `cwd`, falling back to the process working directory when no workspace is supplied. Malformed event data does not fall back to another project. An absent state file is a successful no-op. Legacy state under the installed configuration root is not automatically adopted; confirm its task before migrating it. The scripts do not grant permissions, bypass approvals, or replace client permission systems. +The main agent alone maintains canonical task state. Hooks never write or summarize it, print its contents, or infer completed verification. The task-state hooks use the hook event's `cwd`, falling back to the process working directory when no workspace is supplied. Malformed event data does not fall back to another project. An absent state file is a successful no-op. Legacy state under the installed configuration root is not automatically adopted; confirm its task before migrating it. The scripts do not grant permissions, bypass approvals, or replace client permission systems. + +The QMD warm-up hook uses the process working directory and starts only inside a Git repository when Node.js and the installed wrapper are available. It runs detached; wrapper errors are recorded in `~/.my-ai-configuration/qmd/warm.log`. Disabling local search removes its hook registration. See [Local QMD search](configuration.md#local-qmd-search) for daemon behavior and storage. When enabled during installation or update, Flashbang runs on `Stop`, after the main agent finishes responding. The default flash lasts about 500 milliseconds. The PowerShell command omits `-WindowStyle Hidden`, which can hide or minimize the shared terminal. The PowerShell hook creates a low-opacity click-through overlay without activating another window when its native GUI APIs are available; unsupported runtimes exit safely. Its native DLL cache is optional: a missing `LOCALAPPDATA` environment variable or an unusable cache falls back to in-process compilation instead of suppressing the notification. The Bash hook uses Python's `tkinter`, uses `xrandr` for multi-monitor bounds when available, and falls back to `notify-send` when the overlay is unavailable. Registered hooks are best effort: errors do not fail a Claude session. diff --git a/docs/plugins.md b/docs/plugins.md index c5f36b7..7bf3b22 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -2,7 +2,7 @@ The user-level plugin manifest is `adapters/plugins.tsv`. It maps each logical extension to the client-specific plugin, skill, or MCP installation method. -The current baseline includes Ponytail, i-have-adhd, Superpowers, Context7, Caveman, MCPorter, Humanizer, Impeccable, and Anthropic Frontend Design. Both scripts operate at user scope and show an extension selector unless running a dry run. Selections are collected before configuration changes. Both rebuild generated packages first. +The current baseline includes Ponytail, i-have-adhd, Superpowers, Context7, Caveman, MCPorter, Humanizer, Impeccable, and Anthropic Frontend Design. Install and update operate at user scope and show an extension selector unless running a dry run or Quickupdate. Selections are collected before configuration changes. Both rebuild generated packages before synchronizing client files and extensions. Choosing Auto for local search can prepare and benchmark QMD earlier, during option selection. ### Automatic workflow integration @@ -46,7 +46,16 @@ Codex receives Caveman through its native plugin adapter. Humanizer, Impeccable, On Windows, installation and update repair the known Caveman 1.0.0 hook launcher in setup-owned Codex installations so it resolves the plugin path under PowerShell as well as Command Prompt. Custom commands and foreign installations are preserved. Review the changed hook definitions in Codex `/hooks`; setup does not grant hook trust automatically. -Normal installation and update ask whether to enable Flashbang, apply the custom status line, and enable optional local QMD search (Yes/No/Auto, disabled by default). Local search runs [QMD](https://github.com/tobi/qmd) (`@tobilu/qmd@2.8.3`, Node.js 22 or newer, `npm`) with Qwen3-Embedding-0.6B, Qwen3-Reranker-0.6B, and QMD Query Expansion 1.7B. Auto benchmarks GPU first, then CPU, and enables search only when median search latency is at most 5 s and embedding runs at least 20 chunks/s. While it is enabled, both clients receive the `semantic-search` skill, which the general rules require for questions whose identifiers are unknown; disabling local search removes the skill and its instruction line. The skill calls `qmd-search.mjs`, which reuses a background daemon on loopback 127.0.0.1 protected by a per-start token; the daemon keeps the models loaded and exits after 30 idle minutes (`QMD_IDLE_MINUTES`). A SessionStart hook warms the index and daemon in the background. Models and the index live in `$XDG_CACHE_HOME/qmd` (default `~/.cache/qmd`); the Codex `writable_roots` cover only `~/.cache/qmd`, so a custom `XDG_CACHE_HOME` needs its own writable root. Native Windows packages select the recommended elevated Codex sandbox; its setup can require administrator approval (see [Configuration](configuration.md#permission-defaults)). The previous unelevated mode reproduced `spawnSync git EPERM` during repository-root discovery, before the CLI fallback could run. Runtime search under the elevated mode still needs verification after applying the configuration and starting a new session. The wrapper falls back to the slower QMD CLI path for daemon failures, but that path also needs child-process pipes. Repository collections skip git-ignored paths; the daemon keeps that list as the collection's `ignore` entry in QMD's `index.yml`. The setup saves and restores a user's own QMD `models:` block, and removal touches only the setup-owned package, models, and repository collections; foreign installs and collections survive. Updating migrates from the earlier Python stack by removing `~/.my-ai-configuration/semantic-retrieval/` and old QMD extension ledger records. Quickupdate reuses the saved shell, client, status line, Flashbang, local search, and extension choices without opening menus. Disabling the status line removes its custom setting and setup-owned Claude script. Only successful runs save selections; dry runs do not update extensions or local search. Install and update do not modify the Codex or Claude CLI installations. +### Setup options outside the extension selector + +Flashbang, the custom status line, and local QMD search have separate prompts during install and update. +Quickupdate reuses their saved choices together with the shell, client, and extension selection. Only successful +runs save selections; dry runs do not update extensions or local search. Disabling the status line removes its +custom setting and setup-owned Claude script. + +QMD is managed by the local-search option, not as a plugin. See [Local QMD search](configuration.md#local-qmd-search) +for models, Auto thresholds, runtime behavior, sandbox paths, and ownership-aware removal. +Install and update do not modify the Codex or Claude CLI installations. Plugin installation requires the corresponding client CLI, network access, and any authentication required by the plugin. Context7 may open an OAuth flow. Codex or plugin hooks may require a trust review in `/hooks`. The scripts never install plugins during a build or doctor run and never install them when `--dry-run` or `-DryRun` is used. diff --git a/docs/scripts.md b/docs/scripts.md index 136f891..3b0a73d 100644 --- a/docs/scripts.md +++ b/docs/scripts.md @@ -23,7 +23,7 @@ Run scripts from the repository root. PowerShell and Bash commands have equivale | `commands/doctor.ps1`, `commands/doctor.sh` | Check generated output and installed configuration. | | `commands/prompt-budget.ps1`, `commands/prompt-budget.sh` | Track permanent context, skill metadata, the rule catalog, and agent metadata; warn above 10,000 permanent-context tokens, fail when any token estimate exceeds its baseline by 10%, or permanent context exceeds 15,000 tokens. | | `commands/context-report.ps1`, `commands/context-report.sh` | Report the context installed Claude and Codex actually load, from Claude `/context`, `/skill-doctor`, and its init event, and Codex `debug prompt-input`: categories, active plugins, listed skills, installed skills missing from the listing, and skills listed without description context. `--check` fails on missing or description-less skills. No model request is made. | -| `commands/benchmark.ps1`, `commands/benchmark.sh` | Run the Python, C#/ASP.NET, and TypeScript tasks under `scripts/benchmarks/tasks/` with and without the installed setup. Both arms of a client use one pinned model and reasoning effort; a preflight records what each arm actually loads in `provenance.json` and stops when the arms are not comparable; `--arms setup setup-no-search --tasks 11-* 12-* 13-* --warm-index` compares Claude with and without semantic search on concept-search tasks in a large generated repository, and compare pass rate, rework turns, duration, tokens, tool calls, cost, and workflow checks per task category (`category` in `task.json`: small change, larger implementation, search) (no planning ceremony for a small change, targeted verification for a bugfix, bounded delegation for a larger change). Starts real model sessions; use `--dry-run` to list runs. The Codex baseline needs one `codex login` with `CODEX_HOME` set to `--codex-baseline-home`. | +| `commands/benchmark.ps1`, `commands/benchmark.sh` | Compare real Claude/Codex sessions with and without the setup. See [Session benchmarks](#session-benchmarks) for isolation, costs, and the search comparison. | | `commands/repository-context.ps1`, `commands/repository-context.sh` | Refresh the local repository-context cache. | | `commands/session-state.ps1`, `commands/session-state.sh` | Read or update the local agent session state. | | `commands/telemetry.ps1`, `commands/telemetry.sh` | Append a local telemetry event. | @@ -32,7 +32,14 @@ Run scripts from the repository root. PowerShell and Bash commands have equivale | `commands/add-credentials.ps1`, `commands/add-credentials.sh` | Store a client-scoped tool credential in the operating-system credential store. | | `commands/remove-credentials.ps1`, `commands/remove-credentials.sh` | Delete a selected client-scoped credential from the operating-system credential store. | -Prompt KPIs estimate tokens as UTF-8 bytes divided by four, using the larger shell package per client. Skill metadata counts `SKILL.md` frontmatter outside rule skills; the rule catalog counts all generated rule entry files but excludes references, so it measures the available catalog size rather than rules loaded in a typical session; agent metadata counts frontmatter for Claude and `name`/`description` for Codex. All metrics fail CI above baseline +10%; permanent context also warns above 10,000 tokens and fails above 15,000 tokens. The baseline covers the retained skill catalog. Project-specific instructions, external plugin prompt bodies, and live MCP/tool schemas are not measured. +Prompt KPIs estimate tokens as UTF-8 bytes divided by four, using the larger shell package per client. +Skill metadata counts every `SKILL.md` frontmatter, including Claude's generated rule skills. Permanent context +combines global instructions, skill and agent metadata, and the security baseline loaded for development tasks. +The rule catalog counts Codex rule files outside `references/` and Claude's generated `rules-*/SKILL.md` entries; +it measures available guidance, not all rules loaded in a typical session. Agent metadata counts Claude frontmatter +and Codex `name`/`description` fields. All metrics fail above baseline +10%; permanent context also warns above +10,000 tokens and fails above 15,000. Project instructions, external plugin bodies, and live MCP/tool schemas +are excluded. `context-report` complements this estimate with installed-client discovery. Custom instructions remain under `~/.my-ai-configuration/instructions/`; installation and update scripts never reset their contents. Only clients with a nonempty instruction file receive a startup rule in their installed `AGENTS.md` or `CLAUDE.md`. That rule requires immediate loading before any response or task work and keeps the instructions active throughout the session, including after compaction. Adding or removing instructions refreshes the rule in an existing installation; empty or missing instruction files leave no rule. Generated packages contain no personal instruction rule. Changes apply when the client next loads its global instructions. To undo an added instruction, pass the same text to `remove-instruction` with `-Client`/`--client` and `-Instruction`/`--instruction`. It removes the last exact matching block per selected client and preserves other text. A missing match leaves the file unchanged. @@ -63,7 +70,8 @@ Gitea Actions runs the repository checks from `.gitea/workflows/ci.yml`. | `tests/test-quick-update.py` | Validate saved Quickupdate choices. | | `tests/test-remove-customizations.py` | Validate targeted instruction and credential removal without accessing the real credential store. | | `tests/test-quick-update.ps1`, `tests/test-quick-update.sh` | Run the Quickupdate test through the relevant shell. | -| `tests/test-qmd-*.mjs` | Validate the QMD library, search, daemon, warm-up, and benchmark scripts. | +| `tests/test-qmd-lib.mjs`, `test-qmd-daemon.mjs`, `test-qmd-search.mjs`, `test-qmd-warm.mjs`, `test-qmd-benchmark.mjs` | Model-free QMD unit tests; require the YAML dependency. | +| `tests/test-qmd-integration.mjs` | Manual integration test using real QMD and downloaded models; excluded from CI. | | `tests/test-qmd-setup.py` | Validate QMD installation, migration, and removal. | | `tests/test-session-state.py` | Validate session-state helpers. | | `tests/test-shell-packages.ps1`, `tests/test-shell-packages.sh` | Validate generated package contents and client settings. | @@ -71,8 +79,55 @@ Gitea Actions runs the repository checks from `.gitea/workflows/ci.yml`. | `tests/test-install-selections.ps1`, `tests/test-install-selections.sh` | Validate dry-run shell and client selections. | | `tests/test-command-summaries.ps1`, `tests/test-command-summaries.sh` | Validate doctor, install, and update summary output. | | `tests/test-telemetry.py` | Validate telemetry output. | +| `tests/test-personal-instructions.py` | Validate startup instruction pointers and preservation of personal instruction files. | | `tests/test-user-customizations.py` | Validate user instruction overlays and credential helpers. | +## QMD tests + +The CI `qmd` job installs only `yaml@2.9.0` into an isolated directory, sets `QMD_PACKAGE_DIR` to that directory, +and runs these five files. It does not install QMD or download models. With a complete global QMD installation, +the same tests resolve YAML from QMD automatically: + +```text +node --test scripts/tests/test-qmd-lib.mjs scripts/tests/test-qmd-daemon.mjs scripts/tests/test-qmd-search.mjs scripts/tests/test-qmd-warm.mjs scripts/tests/test-qmd-benchmark.mjs +``` + +Without QMD installed, use the dependency setup from [the CI workflow](../.gitea/workflows/ci.yml). +`QMD_PACKAGE_DIR` must point to the directory containing the test dependency's `node_modules` directory. +A missing YAML dependency fails `test-qmd-lib.mjs` before its tests load. + +Run the integration test separately, only with a complete QMD installation and resources for model downloads. +Unset `QMD_CONFIG_DIR` first so the test uses its temporary configuration rather than an inherited user path. +Clear a unit-test-only `QMD_PACKAGE_DIR` override as well: + +```text +node --test scripts/tests/test-qmd-integration.mjs +``` + +The integration test creates a temporary home and repository, downloads models, searches through the daemon, +and stops it after successful assertions. +Its temporary data is not automatically removed. `QMD_TEST_CACHE` can select an existing QMD cache parent; +the test uses its `qmd/` subdirectory, so avoid pointing it at a cache containing unrelated data. + +## Session benchmarks + +The A/B benchmark runs Python, C#/ASP.NET, and TypeScript tasks under `scripts/benchmarks/tasks/`. +These are real model sessions and can incur usage charges; `--dry-run` lists planned runs. +Both arms use the same model and reasoning effort for each client. Preflight records loaded configuration in +`provenance.json` and normally stops when the arms are not comparable. Reports compare pass rate, rework turns, +time, tokens, tool calls, cost, and workflow checks per task category. + +For Claude's semantic-search comparison, pass these arguments to the shell's benchmark command: + +```text +--clients claude --arms setup setup-no-search --tasks 11-* 12-* 13-* --warm-index +``` + +`setup-no-search` is Claude-only. Warm-up starts QMD and indexes the fixture before timing setup-arm sessions. +The Codex baseline requires a separate login under `--codex-baseline-home`; set `CODEX_HOME` to that path for +`codex login`. Supply `--codex-model` if the installed configuration does not select a model. +Benchmark fixture READMEs describe the starting task state and are retained as test inputs. + ## Internal helpers | Script | Purpose | @@ -90,4 +145,4 @@ Gitea Actions runs the repository checks from `.gitea/workflows/ci.yml`. | `lib/selection-state.py` | Read and write Quickupdate state. | | `lib/qmd.sh`, `lib/qmd.ps1` | Invoke local QMD search from the installation flow. | | `lib/qmd.py` | Install, migrate, benchmark, and remove local QMD search. | -| `shared/qmd/*.mjs` | Installed QMD scripts: search CLI, daemon, warm-up, benchmark, and shared library. | +| [`shared/qmd/`](../shared/qmd/) (repository root) | Installed QMD scripts: search CLI, daemon, warm-up, benchmark, and shared library. | diff --git a/docs/superpowers/plans/2026-10-08-qmd-local-search.md b/docs/superpowers/plans/2026-10-08-qmd-local-search.md deleted file mode 100644 index 154b259..0000000 --- a/docs/superpowers/plans/2026-10-08-qmd-local-search.md +++ /dev/null @@ -1,1972 +0,0 @@ -# QMD Local Search Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Replace the Python Qwen retrieval stack with QMD (Qwen3 embedding, Qwen3 reranker, QMD query expansion) behind the existing Yes/No/Auto local-models question, with a strict `semantic-search` skill for Claude and Codex. - -**Architecture:** Node scripts in `shared/qmd/` drive QMD through its SDK: a token-protected loopback daemon keeps the three models loaded and exits after 30 idle minutes; a search wrapper talks to it and falls back to `qmd query --json`; a SessionStart hook warms the daemon and the repository collection. A Python installer library (`scripts/lib/qmd.py`, with `.sh`/`.ps1` wrappers, the same pattern as the removed `semantic-retrieval.py`) installs, benchmarks, migrates, and removes setup-owned QMD state. - -**Tech Stack:** Node.js 22+ (ESM, `node:test`), `@tobilu/qmd@2.8.3` SDK and its bundled `yaml` and `node-llama-cpp` packages, Python 3.12 stdlib (`unittest`), Bash and PowerShell 5.1/7. - -**Spec:** `docs/superpowers/specs/2026-10-08-qmd-local-search-design.md` - -## Global Constraints - -- Models (exact URIs): embed `hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf`; rerank `hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf`; generate `hf:tobil/qmd-query-expansion-1.7B-gguf/qmd-query-expansion-1.7B-q4_k_m.gguf`. -- QMD package: `@tobilu/qmd@2.8.3`; Node.js 22 or newer; `npm` required. -- No Python code loads or runs a model. Python is used only by the installer library, as elsewhere in `scripts/lib/`. -- Auto thresholds: median search latency at most 5 s (`QMD_BENCHMARK_MAX_QUERY_SECONDS`); embedding at least 20 chunks/s (`QMD_BENCHMARK_MIN_CHUNKS_PER_SECOND`); GPU first, then CPU; 10-minute timeout per device. -- Idle stop: `QMD_IDLE_MINUTES`, default 30. -- Platforms: Linux and Windows are both first-class (the CI runner is Ubuntu; Windows is verified locally in Task 11). Spawned processes use `windowsHide`, `npm`/`qmd` run with `shell: true` only on Windows, hooks have `.sh` and `.ps1` entry points. -- Multiple GPUs and CPUs: the setup never narrows the device set. `gpu` mode uses llama.cpp's automatic backend, which spreads layers over every GPU of that backend; `cpu` mode uses every logical core (node-llama-cpp default). The setup never sets `CUDA_VISIBLE_DEVICES`, `GGML_VK_VISIBLE_DEVICES`, or a thread limit. Mixed-vendor systems use the one backend llama.cpp picks (CUDA before Vulkan); the benchmark reports the GPU names it used. -- Repository collection: `repo-` + first 12 hex chars of SHA-256 of the resolved absolute repository path; mask `**/*.{md,py,cs,ts,tsx,js,jsx,mjs,go,rs,java,ps1,sh,json,yml,yaml,xml,sql}`; chunk strategy `auto`; `includeByDefault: false`. -- State: `~/.my-ai-configuration/qmd.json` (installer state) and `~/.my-ai-configuration/qmd/` (installed scripts, `daemon.json`, `collections.json`, `warm.log`). Selection key stays `semantic_retrieval`; parameters stay `-SemanticRetrieval` / `--semantic-retrieval`. -- The setup removes only what it created: QMD package, model files, repo collections, the `models:` block it wrote. Foreign installs and collections survive. -- Every hook has `.sh` and `.ps1` entry points; PowerShell code stays 5.1-compatible. The `.mjs` scripts are invoked as `node