Notes 22
Capabilities, vulnerabilities and disclosed behavior worth knowing. Nothing here works against the person who installs it, so notes never change the verdict.
Destructive action
mediumNoteConfirmed on reviewhigh confidenceThe config --clear-flashrank path deletes the flashrank model cache directory with shutil.rmtree when the user runs that command, which is the declared cache-clearing purpose and is user-invoked.
shutil.rmtree(cache_dir)
vector:code
Reviewer's reasoning
The rmtree of the flashrank cache runs only on the user-invoked config --clear-flashrank command and is its declared purpose.
Destructive action
mediumNoteConfirmed on reviewhigh confidenceThe local --clean-up command deletes the fastembed model cache directory with shutil.rmtree when the user explicitly runs it, which is the declared cleanup purpose.
shutil.rmtree(cache_dir)
vector:code
Reviewer's reasoning
The fastembed cache rmtree runs only when the user runs local --clean-up, its declared purpose.
Code execution
mediumNoteConfirmed on reviewhigh confidenceThe update --upgrade path runs pip-style upgrade commands for the artifact itself, but only after the user answers a confirmation prompt, so the user decides.
if not typer.confirm(Messages.PROMPT_UPDATE_UPGRADE_CONFIRM):
vector:code
Reviewer's reasoning
The upgrade commands run only after typer.confirm returns true, so the user decides on this self-upgrade of the artifact.
Persistence
mediumNoteConfirmed on reviewhigh confidenceThe alias command appends a shell alias line to the user's shell profile after the user confirms the prompt; the write is user-approved and limited to the declared alias purpose.
profile_path.open("a", encoding="utf-8")vector:code
Reviewer's reasoning
The profile append happens only after the user confirms the alias prompt and is limited to the declared alias purpose.
Code execution
mediumNoteConfirmed on reviewhigh confidenceThe star command runs the local gh CLI to star the project repository when the user invokes it, a declared user-invoked action against the publisher's repo.
subprocess.run(
vector:code
Reviewer's reasoning
The gh repo star call runs only when the user invokes the star command and targets the publisher's repo, as declared.
Code execution
mediumNoteConfirmed on reviewhigh confidenceThe feedback command runs the gh CLI to open a GitHub issue page for the publisher's repository when the user invokes it.
[gh, "issue", "create", "--repo", "scarletkc/vexor", "--web"],
vector:code
Reviewer's reasoning
The feedback command opens a publisher issue page only when the user invokes it.
Code execution
mediumNoteConfirmed on reviewhigh confidenceThe config editor path runs the user's configured editor on the config file when the user runs config with no options; a user-invoked step.
subprocess.run([*cmd_list, str(config_path)], check=True)
vector:code
Reviewer's reasoning
The editor launch runs only when the user runs config with no options, a user-invoked step.
Destructive action
mediumNoteConfirmed on reviewmedium confidenceclear_all_collections unlinks the collections database files; it is not wired to a CLI command in this batch and deletes only the artifact's own store, so it is a note.
candidate.unlink()
vector:code
Reviewer's reasoning
clear_all_collections is not wired to any CLI command in the shown code and only removes the artifact's own store.
Credential access
mediumNoteConfirmed on reviewlow confidenceUndeclared residue: when VEXOR_API_KEY and the Gemini/Voyage keys are absent, resolve_api_key sends the OPENAI_API_KEY to whatever base URL the user configured for the 'custom' provider; this is operator-configured and the key goes only to a user-directed endpoint, so it is a note.
if normalized in {"openai", "custom"}:vector:code
Reviewer's reasoning
The OPENAI_API_KEY fallback goes only to the base URL the user configured for the custom provider, which is a user-chosen endpoint, not an unrelated host.
Persistence
mediumNoteConfirmed on reviewmedium confidenceAlias setup appends a shell alias line to the user's shell profile, but only after the user explicitly confirms with default no; a disclosed, user-decided rc-file write.
handle.write(alias_command + "\n")
vector:code
Reviewer's reasoning
The alias write follows an explicit user confirmation with default no and is the declared alias setup.
Persistence
mediumNoteConfirmed on reviewmedium confidenceSkill installer writes the bundled skill into agent skill directories (auto-detected or user-chosen) after the user confirms; an agent-config write the user opted into for the declared purpose.
result = install_bundled_skill(
vector:code
Reviewer's reasoning
Skill installation happens only after the user answers the install confirmation and picks a target, matching the declared purpose.
Code execution
mediumNoteConfirmed on reviewmedium confidenceInstaller runs pip install of the publisher's own vexor extras through subprocess after the user confirms the prompt; a user-invoked install step that changes only the artifact itself.
completed = subprocess.run(cmd, check=False)
vector:code
Reviewer's reasoning
The pip install of the publisher's own extras runs only after the user confirms the install prompt and changes only the artifact itself.
Data exfiltration
mediumNoteConfirmed on reviewhigh confidenceWith remote rerank configured, the search tool POSTs the query and workspace code snippets, plus the rerank bearer key, to the user-configured endpoint; declared feature, user-chosen destination.
request = urlrequest.Request(config.base_url, data=data, method="POST")
vector:code
Reviewer's reasoning
The POST goes only to a user-configured rerank endpoint carrying the user's own key, a declared feature with a user-chosen destination (test 5, API key for the wrapped service and model endpoint the user chooses).
Destructive action
mediumNoteConfirmed on reviewmedium confidenceWith force enabled, the bundled skill installer deletes an existing destination skill directory with rmtree before copying, a destructive step the user opts into by passing force.
shutil.rmtree(destination)
vector:code
Reviewer's reasoning
The rmtree runs only when the user passes force after a FileExistsError would otherwise occur, so the destructive step is user-opted (test 4).
Persistence
mediumNoteConfirmed on reviewmedium confidenceThe bundled skill is copied into the agent's skills folder (for example ~/.claude/skills), where the agent loads it; this happens only when the user runs the install command with a skills target.
shutil.copytree(source_dir, destination)
vector:code
Reviewer's reasoning
Copying the bundled skill into the agent skills folder happens only when the user runs the install command with a skills target, which is the declared purpose and user-invoked (test 4).
Data exfiltration
mediumNoteConfirmed on reviewmedium confidenceThe remote rerank path sends the search query and result file paths and previews to the user-configured rerank endpoint with the user's API key, a disclosed declared feature.
remote_rerank_request(
vector:code
Reviewer's reasoning
The remote rerank call sends the query and previews to the user-configured endpoint with the user's key, a disclosed declared feature (test 5).
Code execution
mediumNoteConfirmed on reviewmedium confidenceThe upgrade helper runs pip, pipx, uv, or git commands for the publisher's own package only when the user invokes the update-with-upgrade command.
completed = subprocess.run(list(command), check=False, timeout=timeout)
vector:code
Reviewer's reasoning
The helper runs pip, pipx, uv, or git only for the publisher's own package and is invoked only through the user's update-with-upgrade command, so the step is user-opted (test 4).
Supply chain
lowNoteConfirmed on reviewhigh confidenceThe install command copies the bundled agent skill into user-chosen skill directories when the user runs it with --skills, which is the declared purpose and is user-invoked.
install_bundled_skill(
vector:code
Reviewer's reasoning
Skill install copies the bundled skill into directories the user chose via --skills, a declared user-invoked step.
Supply chain
lowNoteConfirmed on reviewhigh confidenceThe MCP server's start-time update check contacts PyPI for the publisher's own package and caches the result, with network use unless disabled by environment or config.
latest = fetch_latest_pypi_version(package, timeout=timeout)
vector:code
Reviewer's reasoning
The start-time check queries PyPI for the publisher's own package and caches the result, which is the artifact's own update path and can be disabled by config (test 5).
Reconnaissance
infoNoteConfirmed on reviewhigh confidenceThe MCP launcher reads the undeclared environment variable VEXOR_MCP_NUM_THREADS and writes it into four BLAS/thread-pool variables via setdefault; this is operator-controlled thread tuning with no data sent off-host, so it is an undeclared but harmless note.
os.environ.setdefault(name, numeric_threads)
vector:code
Reviewer's reasoning
The env var read sets BLAS thread counts for the MCP process only; it is operator-controlled tuning with no outbound data, so it stays a note.
Reconnaissance
infoNoteConfirmed on reviewmedium confidenceThe MCP search and index tools accept an absolute path from the calling agent and read or return that tree (content included by default); this is the declared indexing job on the caller's chosen path.
candidate = Path(raw_path).expanduser()
vector:code
Reviewer's reasoning
The MCP tools read the caller-supplied path as their declared indexing job; the caller chooses the path, so this is the tool doing its job.
Reconnaissance
infoNoteConfirmed on reviewlow confidenceStartup launches a background check against the publisher's release endpoint with the current version; a best-effort, publisher-directed update check.
latest = check_for_update(__version__)
vector:code
Reviewer's reasoning
The startup thread calls the publisher's own PyPI version check, which is the artifact's own update path (test 5) and is best-effort and silent on failure; it does not work against the installer.