# How the tool-index.md Single Source of Truth Works Across Multiple AI Clients

> Discover how tool-index.md acts as a single source of truth for AI clients, enabling consistent tool invocation and verified availability across multiple platforms without hard-coded paths.

- Repository: [ZhaoXu/reverse-skill](https://github.com/zhaoxuya520/reverse-skill)
- Tags: internals
- Published: 2026-09-01

---

**The [`tool-index.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/scripts/refresh-tool-index.sh) |

These scripts perform three operations:

1. **Discover installed binaries** – search common installation directories and `PATH` entries
2. **Resolve actual paths** – handle platform quirks like `r2.bat` fallbacks for Radare2 on Windows
3. **Query versions** – execute `--version` or equivalent flags to capture precise version strings

The scripts output two artefacts:

- [`skills/tool-index.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/tool-index.md) – human-readable Markdown table
- [`skills/tool-index.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) follows a consistent pipe-delimited pattern:

```markdown
| 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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/routing.md), the generic routing guide states:

> Check [`tool-index.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) for 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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/ida-reverse/SKILL.md) and [`skills/radare2/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/radare2/SKILL.md), the workflow includes:

```

NEXT: Read ../tool-index.md to validate tool availability and actual path

```

By reading [`tool-index.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) (or [`tool-index.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.json)), an AI client obtains four critical facts:

- **Existence verified** – the `Available` column confirms the binary is present
- **Exact executable path** – essential on Windows where wrappers like `r2.bat` replace 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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/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:

```powershell

# Windows

powershell -NoProfile -ExecutionPolicy Bypass `
    -File "skills/scripts/refresh-tool-index.ps1"

```

```bash

# 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:

1. **No path guessing** – Any skill attempting to invoke a hard-coded path without checking [`tool-index.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) is flagged as a violation during code review or automated linting.

2. **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

```powershell

# 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

```bash

# 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

```python
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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/scripts/refresh-tool-index.sh) | Linux/macOS Bash counterpart |
| [`skills/routing.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/routing.md) | Routing documentation mandating catalogue checks |
| [`skills/ida-reverse/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/ida-reverse/SKILL.md) | Representative skill showing "read catalogue" NEXT step |
| [`skills/radare2/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/radare2/SKILL.md) | Another skill with identical validation pattern |

---

## Summary

- **[`tool-index.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) is 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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) and [`tool-index.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/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`](https://github.com/zhaoxuya520/reverse-skill/blob/main/tool-index.md) and the `version` field in [`tool-index.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/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.