How the tool-index.md Single Source of Truth Works Across Multiple AI Clients
The tool-index.md file in zhaoxuya520/reverse-skill is an auto-generated, machine-specific catalogue that every AI client must read before invoking any external tool, ensuring consistent, verified tool availability without hard-coded paths.
The tool-index.md single source of truth pattern solves a critical problem in multi-client AI systems: how do Claude, OpenAI, Cursor, and other agents reliably discover and invoke external tools like Radare2 or IDA Pro when each host machine has different installation paths and versions? Rather than embedding platform-specific logic into every skill, reverse-skill centralizes tool discovery into a git-ignored, auto-generated file that all clients consume uniformly.
Auto-Generation: How tool-index.md Gets Created
The tool-index.md file is never hand-edited. It is produced by refresh scripts that run on each host machine:
| Platform | Script Location |
|---|---|
| Windows PowerShell | skills/scripts/refresh-tool-index.ps1 |
| Linux/macOS Bash | skills/scripts/refresh-tool-index.sh |
These scripts perform three operations:
- Discover installed binaries – search common installation directories and
PATHentries - Resolve actual paths – handle platform quirks like
r2.batfallbacks for Radare2 on Windows - Query versions – execute
--versionor equivalent flags to capture precise version strings
The scripts output two artefacts:
skills/tool-index.md– human-readable Markdown tableskills/tool-index.json– machine-readable JSON for programmatic consumers
The template file at skills/tool-index.md.template documents the format and explains why the real file is .gitignore-d: it varies per machine and must not be committed.
Structure of the Catalogue
Each line in tool-index.md follows a consistent pipe-delimited pattern:
| Tool | Available | Version | Path | Source |
| ---- | --------- | ------- | ---- | ------ |
| r2 | ✓ | 6.2.0 | r2.bat | FallbackPath |
| ida | ✗ | — | — | NotInstalled |
The symbols are defined in the template:
- ✓ = Tool is available and executable
- ✗ = Tool not found or not executable
The Source column indicates how the path was resolved—direct PATH lookup, explicit installation directory, or fallback heuristic.
Consumption by AI Clients
All skill Markdown files in the repository mandate reading the catalogue before executing any external command. This creates a forced validation gate.
In skills/routing.md, the generic routing guide states:
Check
tool-index.mdfor actual tool availability, paths, and versions. NEVER guess paths.
Individual skill files embed this as a formal NEXT step. For example, in skills/ida-reverse/SKILL.md and skills/radare2/SKILL.md, the workflow includes:
NEXT: Read ../tool-index.md to validate tool availability and actual path
By reading tool-index.md (or tool-index.json), an AI client obtains four critical facts:
- Existence verified – the
Availablecolumn confirms the binary is present - Exact executable path – essential on Windows where wrappers like
r2.batreplace direct binary names - Version for feature detection – determine if a specific command-line flag is supported
- Platform abstraction – no hard-coded paths that break across different machines
Cross-Client Consistency
The design achieves single source of truth status through architectural enforcement:
| Aspect | Implementation |
|---|---|
| Client-agnostic generation | Refresh scripts only write files; they do not know which AI client will read them |
| Unified consumption contract | Every skill file uses identical "read catalogue first" wording |
| Local state, global pattern | Each host generates its own tool-index.md, but all follow the same schema |
| Runtime freshness | Tool installations or upgrades trigger a refresh; subsequent skill runs see new state immediately |
This means Claude on Windows, Cursor on macOS, and an OpenAI agent in a Linux container all follow identical logic: generate locally, read locally, execute confidently.
Refresh Lifecycle and Security Guarantees
Refresh Workflow
When tools change on a host, the user runs the appropriate script:
# Windows
powershell -NoProfile -ExecutionPolicy Bypass `
-File "skills/scripts/refresh-tool-index.ps1"
# Linux/macOS
bash skills/scripts/refresh-tool-index.sh
Both scripts atomically update .md and .json, ensuring no stale state persists.
Security Rules
The architecture enforces two hard constraints:
-
No path guessing – Any skill attempting to invoke a hard-coded path without checking
tool-index.mdis flagged as a violation during code review or automated linting. -
No private data leakage – The generated files appear in
.gitignore, preventing accidental commits that would expose machine-specific paths, usernames in directory structures, or internal version numbers.
Practical Code Examples
PowerShell: Refresh and Query
# Refresh the tool index on Windows
powershell -NoProfile -ExecutionPolicy Bypass `
-File "skills/scripts/refresh-tool-index.ps1"
# Parse the catalogue for Radare2 availability
$toolIndex = Get-Content "skills/tool-index.md" |
Where-Object { $_ -match '\| r2 \|' } |
ConvertFrom-String -Delimiter '|' -PropertyNames Tool,Available,Version,Path,Source
if ($toolIndex.Available -eq '✓') {
Write-Host "Radare2 is available at $($toolIndex.Path) (v$($toolIndex.Version))"
& $toolIndex.Path --help
} else {
Write-Error "Radare2 not installed – aborting."
}
Bash: Refresh and Extract
# Refresh the tool index on Linux/macOS
bash skills/scripts/refresh-tool-index.sh
# Extract Radare2 path using awk
tool_path=$(awk -F'|' '/\| r2 \|/ {print $4}' skills/tool-index.md | xargs)
tool_version=$(awk -F'|' '/\| r2 \|/ {print $3}' skills/tool-index.md | xargs)
if [[ -n "$tool_path" ]]; then
echo "Radare2 $tool_version found at $tool_path"
"$tool_path" --version
else
echo "Radare2 not installed – exiting."
exit 1
fi
Python: JSON Consumption for LLM Agents
import json
import pathlib
# Read the machine-readable JSON catalogue
idx = json.loads(pathfile.Path("skills/tool-index.json").read_text())
# Validate and invoke Radare2
r2 = idx.get("r2")
if r2 and r2["available"]:
print(f"Radare2 {r2['version']} at {r2['path']}")
# Proceed with tool invocation...
else:
raise RuntimeError("Radare2 missing from tool-index.json; run refresh script")
Key Files in the Implementation
| File | Purpose |
|---|---|
skills/tool-index.md.template |
Blueprint explaining format symbols and git-ignore policy |
skills/scripts/refresh-tool-index.ps1 |
Windows PowerShell discovery and generation script |
skills/scripts/refresh-tool-index.sh |
Linux/macOS Bash counterpart |
skills/routing.md |
Routing documentation mandating catalogue checks |
skills/ida-reverse/SKILL.md |
Representative skill showing "read catalogue" NEXT step |
skills/radare2/SKILL.md |
Another skill with identical validation pattern |
Summary
tool-index.mdis auto-generated, not hand-maintained – refresh scripts discover tools, resolve paths, and query versions on each host- Two output formats – Markdown for human inspection, JSON for programmatic parsing
- Forced consumption pattern – every skill must read the catalogue before invoking tools, preventing hard-coded path assumptions
- Single source of truth across clients – Claude, OpenAI, Cursor, and others all consume the same locally-generated file using identical logic
- Security by design – git-ignored output prevents data leakage; mandatory catalogue checks prevent path guessing
Frequently Asked Questions
What happens if I don't run the refresh script after installing a new tool?
The tool-index.md and tool-index.json files retain their previous state. Any skill checking for the new tool will see ✗ or missing entries, causing the workflow to abort or skip that tool. Run the appropriate refresh script to update the catalogue.
Can multiple AI clients share one tool-index.md file across networked machines?
No. The file is intentionally machine-specific and .gitignore-d. Each host must run its own refresh script to capture local paths like C:\Program Files\Radare2\bin\r2.bat versus /usr/bin/r2. Sharing the file would break path resolution.
Why provide both Markdown and JSON versions?
Markdown serves human debugging and quick inspection during development. JSON provides structured data for LLM-driven agents and programmatic clients that parse the catalogue automatically. The refresh scripts maintain both in sync.
How does the system handle version-dependent features?
The Version column in tool-index.md and the version field in tool-index.json expose precise version strings. Skills can implement conditional logic—parsing semantic versions to determine if a specific command-line flag is supported before attempting execution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →