Compare commits

..
8 Commits
25 changed files with 105 additions and 134 deletions

No files matched your search

-31
View File
@@ -1,31 +0,0 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|apply_patch",
"hooks": [
{
"type": "command",
"command": "[ ! -f 'C:\\Users\\j.lechner\\.agents\\skills\\impeccable\\scripts\\impeccable' ] || 'C:\\Users\\j.lechner\\.agents\\skills\\impeccable\\scripts\\impeccable' hook",
"commandWindows": "powershell -NoProfile -NonInteractive -EncodedCommand JABQAHIAbwBnAHIAZQBzAHMAUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwA7ACAAaQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAC0ATABpAHQAZQByAGEAbABQAGEAdABoACAAJwBDADoALwBVAHMAZQByAHMALwBqAC4AbABlAGMAaABuAGUAcgAvAC4AYQBnAGUAbgB0AHMALwBzAGsAaQBsAGwAcwAvAGkAbQBwAGUAYwBjAGEAYgBsAGUALwBzAGMAcgBpAHAAdABzAC8AaQBtAHAAZQBjAGMAYQBiAGwAZQAuAGMAbQBkACcAKQAgAHsAIAAmACAAJwBDADoALwBVAHMAZQByAHMALwBqAC4AbABlAGMAaABuAGUAcgAvAC4AYQBnAGUAbgB0AHMALwBzAGsAaQBsAGwAcwAvAGkAbQBwAGUAYwBjAGEAYgBsAGUALwBzAGMAcgBpAHAAdABzAC8AaQBtAHAAZQBjAGMAYQBiAGwAZQAuAGMAbQBkACcAIABoAG8AbwBrADsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0A",
"timeout": 5,
"statusMessage": "Checking UI changes"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "[ ! -f 'C:\\Users\\j.lechner\\.agents\\skills\\impeccable\\scripts\\impeccable' ] || 'C:\\Users\\j.lechner\\.agents\\skills\\impeccable\\scripts\\impeccable' hook",
"commandWindows": "powershell -NoProfile -NonInteractive -EncodedCommand JABQAHIAbwBnAHIAZQBzAHMAUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwA7ACAAaQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAC0ATABpAHQAZQByAGEAbABQAGEAdABoACAAJwBDADoALwBVAHMAZQByAHMALwBqAC4AbABlAGMAaABuAGUAcgAvAC4AYQBnAGUAbgB0AHMALwBzAGsAaQBsAGwAcwAvAGkAbQBwAGUAYwBjAGEAYgBsAGUALwBzAGMAcgBpAHAAdABzAC8AaQBtAHAAZQBjAGMAYQBiAGwAZQAuAGMAbQBkACcAKQAgAHsAIAAmACAAJwBDADoALwBVAHMAZQByAHMALwBqAC4AbABlAGMAaABuAGUAcgAvAC4AYQBnAGUAbgB0AHMALwBzAGsAaQBsAGwAcwAvAGkAbQBwAGUAYwBjAGEAYgBsAGUALwBzAGMAcgBpAHAAdABzAC8AaQBtAHAAZQBjAGMAYQBiAGwAZQAuAGMAbQBkACcAIABoAG8AbwBrADsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0A",
"timeout": 30,
"statusMessage": "Design deep pass"
}
]
}
]
}
}
+30 -79
View File
@@ -1,4 +1,4 @@
name: CI
name: CI
on:
push:
@@ -12,85 +12,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Check Linux tooling
run: |
command -v pwsh >/dev/null || { echo 'pwsh is required on the Linux runner'; exit 1; }
- name: Bash syntax
run: find scripts shared/hooks -name '*.sh' -print0 | xargs -0 -n1 bash -n
- name: Capability checks
run: ./scripts/check-capabilities.sh
- name: Build
run: ./scripts/build.sh --summary
- name: Prompt budget
run: ./scripts/prompt-budget.sh --summary
- name: Repository context cache
run: ./scripts/repository-context.sh --summary
- name: Doctor
run: ./scripts/doctor.sh --summary
shell: bash
run: git ls-files -z '*.sh' | xargs -0 -r -n1 bash -n
- name: PowerShell syntax
run: |
find scripts shared/hooks -name '*.ps1' -print0 | xargs -0 -n1 pwsh -NoProfile -Command '$tokens=$null; $errors=$null; [System.Management.Automation.Language.Parser]::ParseFile($args[0],[ref]$tokens,[ref]$errors) | Out-Null; if ($errors.Count) { $errors | % { Write-Error $_ }; exit 1 }'
- name: PowerShell build and validation
shell: pwsh
run: |
$env:REQUIRE_CODEX_SCHEMA = 'true'
./scripts/check-capabilities.ps1
./scripts/build.ps1 -Summary
./scripts/doctor.ps1 -Summary
./scripts/test-shell-packages.ps1 -Summary
./scripts/test-managed-install.ps1 -Summary
./scripts/test-build-validation.ps1 -Summary
./scripts/test-install-guards.ps1 -Summary
./scripts/test-plugin-selection.ps1 -Summary
./scripts/test-quick-update.ps1 -Summary
python ./scripts/test-install-options.py
python ./scripts/test-quick-update.py
python ./scripts/test-managed-extensions.py
python ./scripts/test-session-state.py
python ./scripts/test-telemetry.py
python ./scripts/test-semantic-retrieval.py
./scripts/install.ps1 -Summary -DryRun -Client Both -Shell PowerShell
./scripts/update.ps1 -Summary -DryRun -Client Both -Shell PowerShell
- name: Shell package tests
run: ./scripts/test-shell-packages.sh --summary
- name: Managed manifest tests
run: ./scripts/test-managed-install.sh --summary
- name: Build validation tests
run: ./scripts/test-build-validation.sh --summary
- name: Install guard tests
run: ./scripts/test-install-guards.sh --summary
- name: Plugin selection tests
run: ./scripts/test-plugin-selection.sh --summary
- name: Quick-update and install-option tests
run: |
./scripts/test-quick-update.sh --summary
python3 scripts/test-install-options.py
python3 scripts/test-telemetry.py
python3 scripts/test-semantic-retrieval.py
- name: Managed extension and session-state tests
run: |
python3 scripts/test-managed-extensions.py
python3 scripts/test-session-state.py
- name: Install dry run
run: |
export HOME="$RUNNER_TEMP/isolated-home"
mkdir -p "$HOME"
./scripts/install.sh --summary --dry-run --client both --platform linux
- name: Update dry run
run: |
export HOME="$RUNNER_TEMP/isolated-home"
mkdir -p "$HOME"
./scripts/update.sh --summary --dry-run --client both --platform linux
compatibility-canary:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Latest external clients
run: npm install --global @openai/codex@latest
- name: Latest-client schema and dry runs
run: |
REQUIRE_CODEX_SCHEMA=true ./scripts/build.sh --summary
HOME="$RUNNER_TEMP/canary-home" ./scripts/install.sh --summary --dry-run --client both --platform linux
HOME="$RUNNER_TEMP/canary-home" ./scripts/update.sh --summary --dry-run --client both --platform linux
$ErrorActionPreference = 'Stop'
$failed = $false
foreach ($file in (git ls-files '*.ps1')) {
$tokens = $null
$parseErrors = $null
[System.Management.Automation.Language.Parser]::ParseFile((Join-Path $PWD $file), [ref]$tokens, [ref]$parseErrors) | Out-Null
if ($parseErrors.Count) {
$parseErrors | ForEach-Object { Write-Host "${file}: $_" }
$failed = $true
}
}
if ($failed) { exit 1 }
- name: Build
shell: bash
run: bash scripts/build.sh --summary
- name: Bash install dry run
shell: bash
run: bash scripts/install.sh --summary --dry-run --client both --shell bash
- name: Bash update dry run
shell: bash
run: bash scripts/update.sh --summary --dry-run --client both --shell bash
- name: PowerShell install dry run
shell: pwsh
run: ./scripts/install.ps1 -Summary -DryRun -Client Both -Shell PowerShell
- name: PowerShell update dry run
shell: pwsh
run: ./scripts/update.ps1 -Summary -DryRun -Client Both -Shell PowerShell
+4 -5
View File
@@ -211,7 +211,7 @@ and replaced, with a warning. Untracked files outside package target paths are l
Previously managed files no longer shipped are backed up and removed if unchanged. If locally modified, they are
backed up and retained with a warning. Backups are stored under `backups/<timestamp>/` in each destination.
Local Codex `model`, `reasoning_effort`, `plugins`, and `marketplaces` settings are preserved when syncing `config.toml`;
Local Codex `model`, `model_reasoning_effort`, `plugins`, and `marketplaces` settings are preserved when syncing `config.toml`;
other local settings are not generally merged. Dry runs still rebuild `generated/`, but do not modify installation destinations.
Selecting Codex also installs shared skills to `.agents/skills`. An interactive extension list includes plugins and
@@ -296,10 +296,9 @@ turning yellow at 60% and red at 85%; its status-line input does not expose the
### Add a rule
Create a focused Markdown file in `shared/rules/`. For a rule that applies only to a language, framework, tool, or
change area, add a row to `adapters/claude/rule-skills.tsv` (Claude generates it as a skill) and add its loading
condition to the Codex rule-loading text in `scripts/build.ps1`/`scripts/build.sh` (Codex loads it as a plain file, by
path). Put always-applicable guidance in `general.md`, which the build embeds for both clients; a new rule file is
not automatically embedded.
change area, add one row to `adapters/claude/rule-skills.tsv`. The build uses that manifest to generate both Claude's
rule skill and Codex's rule-loading condition. Put always-applicable guidance in `general.md`, which the build embeds
for both clients; a new rule file is not automatically embedded.
### Add a skill
+1 -1
View File
@@ -1 +1 @@
{"Claude permanent context":5030,"Codex permanent context":4828,"Claude permanent context absolute limit":6500,"Codex permanent context absolute limit":6500}
{"Claude permanent context":7101,"Codex permanent context":7377,"Claude permanent context absolute limit":8000,"Codex permanent context absolute limit":8000}
+2 -2
View File
@@ -1,2 +1,2 @@
Claude 5030 6500
Codex 4828 6500
Claude 7101 8000
Codex 7377 8000
1 Claude 5030 7101 6500 8000
2 Codex 4828 7377 6500 8000
+1 -1
View File
@@ -24,7 +24,7 @@ function Read-InstallOptions {
return @{
update_agents = Read-InstallBoolean -Prompt "Update selected agent CLIs ($Client)?" -Default $defaults.update_agents
flashbang = Read-InstallBoolean -Prompt 'Enable the Flashbang notification hook?' -Default $defaults.flashbang
semantic_retrieval = Read-InstallBoolean -Prompt 'Enable Qwen3-Embedding-0.6B semantic retrieval?' -Default $defaults.semantic_retrieval
semantic_retrieval = Read-InstallBoolean -Prompt 'Enable Qwen3 embedding and reranking semantic retrieval?' -Default $defaults.semantic_retrieval
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ read_install_options() {
[ "$dry_run" = false ] || return 0
update_agents=$(read_install_boolean "Update selected agent CLIs ($client)?" "$update_agents") || return
flashbang=$(read_install_boolean 'Enable the Flashbang notification hook?' "$flashbang") || return
semantic_retrieval=$(read_install_boolean 'Enable Qwen3-Embedding-0.6B semantic retrieval?' "$semantic_retrieval") || return
semantic_retrieval=$(read_install_boolean 'Enable Qwen3 embedding and reranking semantic retrieval?' "$semantic_retrieval") || return
}
is_windows_host() {
+1 -1
View File
@@ -87,7 +87,7 @@ function Sync-ManagedDestination {
$localConfig = [System.IO.File]::ReadAllText($target)
$pluginTables = [regex]::Matches($localConfig, '(?m)^[ \t]*\[(?:plugins|marketplaces)(?:\.|\])[\s\S]*?(?=^[ \t]*\[|\z)')
$rootConfig = [regex]::Split($localConfig, '(?m)^[ \t]*\[', 2)[0]
$localSettings = [regex]::Matches($rootConfig, '(?m)^[ \t]*(?:model|reasoning_effort)[ \t]*=.*$')
$localSettings = [regex]::Matches($rootConfig, '(?m)^[ \t]*(?:model|model_reasoning_effort)[ \t]*=.*$')
if ($localSettings.Count -gt 0) {
$content = [System.Text.Encoding]::UTF8.GetString($newBytes).TrimEnd([char[]]"`r`n")
foreach ($setting in $localSettings) {
+1 -1
View File
@@ -87,7 +87,7 @@ sync_managed_destination() {
local plugin_tables local_settings setting_name
local_settings=$(awk '
/^[ \t]*\[/ { exit }
/^[ \t]*(model|reasoning_effort)[ \t]*=/ { print }
/^[ \t]*(model|model_reasoning_effort)[ \t]*=/ { print }
' "$target")
if [ -n "$local_settings" ]; then
while IFS= read -r setting; do
+1 -1
View File
@@ -96,7 +96,7 @@ def sync(root, home, clients, enabled, dry_run, update):
if target.exists() and not state['files']:
raise ValueError('Semantic retrieval directory exists without setup ownership; refusing to overwrite it.')
if dry_run:
print('DRYRUN enable semantic retrieval: Qwen3-Embedding-0.6B')
print('DRYRUN enable semantic retrieval: Qwen3-Embedding-0.6B + Qwen3-Reranker-0.6B')
return
target.mkdir(parents=True, exist_ok=True)
source = root / 'shared' / 'retrieval'
Regular → Executable
View File
File mode changed.
Regular → Executable
View File
File mode changed.
Regular → Executable
View File
File mode changed.
Regular → Executable
View File
File mode changed.
Regular → Executable
View File
File mode changed.
+3 -3
View File
@@ -54,15 +54,15 @@ try {
[plugins."disabled@market"]
enabled = false
'@
[System.IO.File]::WriteAllText((Join-Path $source 'config.toml'), "model = 'new'`nreasoning_effort = 'low'`n")
[System.IO.File]::WriteAllText($configPath, "model = 'old'`nreasoning_effort = 'high'`n$pluginState`n[other]`nvalue = true`n")
[System.IO.File]::WriteAllText((Join-Path $source 'config.toml'), "model = 'new'`nmodel_reasoning_effort = 'low'`napprovals_reviewer = 'auto_review'`n")
[System.IO.File]::WriteAllText($configPath, "model = 'old'`nmodel_reasoning_effort = 'high'`napprovals_reviewer = 'user'`n$pluginState`n[other]`nvalue = true`n")
$originalConfig = [System.IO.File]::ReadAllText($configPath)
$null = Sync-ManagedDestination -Source $source -Destination $destination -Stamp 'plugins-dry' -DryRun
if ([System.IO.File]::ReadAllText($configPath) -ne $originalConfig) { throw 'Dry run must preserve plugin configuration.' }
$null = Sync-ManagedDestination -Source $source -Destination $destination -Stamp 'plugins'
$mergedConfig = [System.IO.File]::ReadAllText($configPath)
if (-not ($mergedConfig -replace "`r`n", "`n").Contains(($pluginState -replace "`r`n", "`n"))) { throw 'Updating config.toml must preserve local marketplace and plugin tables, including disabled plugins.' }
if (-not $mergedConfig.Contains("model = 'old'") -or -not $mergedConfig.Contains("reasoning_effort = 'high'") -or $mergedConfig.Contains("model = 'new'") -or $mergedConfig.Contains("reasoning_effort = 'low'") -or $mergedConfig.Contains('[other]')) { throw 'Updating config.toml must preserve local model and reasoning effort while updating managed configuration.' }
if (-not $mergedConfig.Contains("model = 'old'") -or -not $mergedConfig.Contains("model_reasoning_effort = 'high'") -or -not $mergedConfig.Contains("approvals_reviewer = 'auto_review'") -or $mergedConfig.Contains("model = 'new'") -or $mergedConfig.Contains("model_reasoning_effort = 'low'") -or $mergedConfig.Contains("approvals_reviewer = 'user'") -or $mergedConfig.Contains('[other]')) { throw 'Updating config.toml must preserve local model settings and enforce automatic review.' }
if ([System.IO.File]::ReadAllText((Join-Path $destination 'backups/plugins/config.toml')) -ne $originalConfig) { throw 'Original plugin configuration must be backed up.' }
$null = Sync-ManagedDestination -Source $source -Destination $destination -Stamp 'plugins-repeat'
if ([System.IO.File]::ReadAllText($configPath) -ne $mergedConfig -or (Test-Path (Join-Path $destination 'backups/plugins-repeat'))) { throw 'Preserving plugin configuration must be idempotent.' }
+3 -3
View File
@@ -58,8 +58,8 @@ plugin_state=' [marketplaces.ponytail]
enabled = true
[plugins."disabled@market"]
enabled = false'
printf "model = 'new'\nreasoning_effort = 'low'\n" > "$source_dir/config.toml"
printf "model = 'old'\nreasoning_effort = 'high'\n%s\n[other]\nvalue = true\n" "$plugin_state" > "$destination/config.toml"
printf "model = 'new'\nmodel_reasoning_effort = 'low'\napprovals_reviewer = 'auto_review'\n" > "$source_dir/config.toml"
printf "model = 'old'\nmodel_reasoning_effort = 'high'\napprovals_reviewer = 'user'\n%s\n[other]\nvalue = true\n" "$plugin_state" > "$destination/config.toml"
original_config=$(cat "$destination/config.toml")
sync_managed_destination "$source_dir" "$destination" plugins-dry "" "" "" true > /dev/null
[ "$(cat "$destination/config.toml")" = "$original_config" ] || { printf 'Dry run changed plugin configuration.\n' >&2; exit 1; }
@@ -68,7 +68,7 @@ merged_config=$(cat "$destination/config.toml")
merged_config_normalized=${merged_config//$'\r'/}
plugin_state_normalized=${plugin_state//$'\r'/}
[[ "$merged_config_normalized" == *"$plugin_state_normalized"* ]] || { printf 'Updating config.toml must preserve local marketplace and plugin tables, including disabled plugins.\n' >&2; exit 1; }
[[ "$merged_config" == *"model = 'old'"* && "$merged_config" == *"reasoning_effort = 'high'"* && "$merged_config" != *"model = 'new'"* && "$merged_config" != *"reasoning_effort = 'low'"* && "$merged_config" != *'[other]'* ]] || { printf 'Updating config.toml must preserve local model and reasoning effort while updating managed configuration.\n' >&2; exit 1; }
[[ "$merged_config" == *"model = 'old'"* && "$merged_config" == *"model_reasoning_effort = 'high'"* && "$merged_config" == *"approvals_reviewer = 'auto_review'"* && "$merged_config" != *"model = 'new'"* && "$merged_config" != *"model_reasoning_effort = 'low'"* && "$merged_config" != *"approvals_reviewer = 'user'"* && "$merged_config" != *'[other]'* ]] || { printf 'Updating config.toml must preserve local model settings and enforce automatic review.\n' >&2; exit 1; }
[ "$(cat "$destination/backups/plugins/config.toml")" = "$original_config" ] || { printf 'Original plugin configuration must be backed up.\n' >&2; exit 1; }
sync_managed_destination "$source_dir" "$destination" plugins-repeat "" "" "" false > /dev/null
[ "$(cat "$destination/config.toml")" = "$merged_config" ] && [ ! -d "$destination/backups/plugins-repeat" ] || { printf 'Preserving plugin configuration must be idempotent.\n' >&2; exit 1; }
Regular → Executable
View File
File mode changed.
Regular → Executable
View File
File mode changed.
+36
View File
@@ -0,0 +1,36 @@
import importlib.util
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parent.parent
SPEC = importlib.util.spec_from_file_location('retrieval_server', ROOT / 'shared/retrieval/server.py')
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
class RetrievalServerTests(unittest.TestCase):
def test_rerank_uses_cross_encoder_scores(self):
index = MODULE.Index.__new__(MODULE.Index)
class Reranker:
def predict(self, pairs):
self.pairs = pairs
return [0.1, 0.8, 0.5]
reranker = Reranker()
index.reranker = lambda: reranker
rows = [
{'path': 'a.md', 'score': 0.9, 'text': 'first'},
{'path': 'b.md', 'score': 0.8, 'text': 'second'},
{'path': 'c.md', 'score': 0.7, 'text': 'third'},
]
result = index.rerank('query', rows, 2)
self.assertEqual([item['path'] for item in result], ['b.md', 'c.md'])
self.assertEqual(reranker.pairs, [('query', 'first'), ('query', 'second'), ('query', 'third')])
if __name__ == '__main__':
unittest.main()
Regular → Executable
View File
File mode changed.
Regular → Executable
View File
File mode changed.
+1 -1
View File
@@ -1,2 +1,2 @@
mcp>=1.9,<2
sentence-transformers>=4.1,<5
sentence-transformers>=5.4,<6
+19 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Local MCP semantic search backed by Qwen3-Embedding-0.6B."""
"""Local MCP semantic search backed by Qwen3 embedding and reranking."""
from __future__ import annotations
@@ -11,6 +11,7 @@ import sqlite3
MODEL = "Qwen/Qwen3-Embedding-0.6B"
RERANKER_MODEL = "Qwen/Qwen3-Reranker-0.6B"
TEXT_EXTENSIONS = {".c", ".cpp", ".cs", ".go", ".java", ".js", ".json", ".md", ".py", ".ps1", ".rs", ".sh", ".toml", ".ts", ".tsx", ".txt", ".yaml", ".yml"}
@@ -31,6 +32,7 @@ class Index:
self.db.execute("create table if not exists chunks (path text, text text, vector blob)")
self.db.commit()
self.model = None
self.reranker_model = None
def files(self):
ignored = {".git", ".venv", "generated", "node_modules", ".my-ai-configuration"}
@@ -49,6 +51,19 @@ class Index:
self.model = SentenceTransformer(MODEL)
return self.model
def reranker(self):
if self.reranker_model is None:
from sentence_transformers import CrossEncoder
self.reranker_model = CrossEncoder(RERANKER_MODEL)
return self.reranker_model
def rerank(self, query: str, rows: list[dict], limit: int):
candidates = rows[:min(len(rows), max(limit, 20))]
scores = self.reranker().predict([(query, item["text"]) for item in candidates])
for item, score in zip(candidates, scores):
item["score"] = round(float(score), 6)
return sorted(candidates, key=lambda item: item["score"], reverse=True)[:limit]
def rebuild(self):
encoder = self.encoder()
values = []
@@ -73,7 +88,8 @@ class Index:
import numpy as np
score = float(np.dot(vector, np.frombuffer(blob, dtype=np.float32)))
rows.append({"path": path, "score": round(score, 6), "text": text})
return sorted(rows, key=lambda item: item["score"], reverse=True)[:max(1, min(top_k, 20))]
limit = max(1, min(top_k, 20))
return self.rerank(query, sorted(rows, key=lambda item: item["score"], reverse=True), limit)
def main():
@@ -91,7 +107,7 @@ def main():
@mcp.tool()
def semantic_search(query: str, top_k: int = 5) -> list[dict]:
"""Find repository passages by meaning with Qwen3-Embedding-0.6B."""
"""Find repository passages with Qwen3 embedding and reranking."""
return index.search(query, top_k)
@mcp.tool()
+1 -1
View File
@@ -21,7 +21,7 @@ Project instructions may specialize global defaults, but must not weaken securit
## Semantic repository search
* In Codex and Claude Code, proactively use Qwen3-Embedding-0.6B through the `my-ai-qwen3-retrieval` MCP server's `semantic_search` tool whenever available and useful. Discover the tool if it is not already exposed.
* In Codex and Claude Code, proactively use the `my-ai-qwen3-retrieval` MCP server's `semantic_search` tool whenever available and useful. It always uses Qwen3-Embedding-0.6B for retrieval and Qwen3-Reranker-0.6B for reranking. Discover the tool if it is not already exposed.
* Use semantic search early to find unfamiliar code, understand responsibilities and relationships, locate similar implementations, or investigate behavior described without exact symbols. Reuse relevant results and search again when a new question would benefit.
* Use direct file reads for known paths and exact text search for symbols, literals, and exhaustive caller checks. Combine these with semantic search when meaning-based discovery adds value.
* Treat retrieved passages as leads: verify them against current files in the intended workspace before relying on them. Empty results do not prove absence; stale or unrelated results require direct inspection.