- .NET 10 SDK or later
dotnet tool install -g ASTralThen run:
astralgit clone https://github.com/Atypical-Consulting/ASTral.git
cd ASTral
dotnet buildTo publish as a standalone tool:
dotnet publish src/ASTral/ASTral.csproj -c Release -o ./publishAdd to your claude_desktop_config.json:
{
"mcpServers": {
"astral": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/ASTral/src/ASTral"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx",
"ANTHROPIC_API_KEY": "sk-ant-xxxxxxxx"
}
}
}
}Or if using a published binary:
{
"mcpServers": {
"astral": {
"command": "/path/to/publish/ASTral",
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx",
"ANTHROPIC_API_KEY": "sk-ant-xxxxxxxx"
}
}
}
}Both environment variables are optional:
GITHUB_TOKENenables private repositories and higher GitHub API rate limits.ANTHROPIC_API_KEYenables AI-generated summaries via Claude Haiku.- If not set, summaries fall back to docstrings or signatures.
Add to .vscode/settings.json:
{
"mcp.servers": {
"astral": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/ASTral/src/ASTral"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx"
}
}
}
}If you use Claude Code, you can display a live token savings counter in the status bar:
Claude Sonnet 4.6 | my-project | 1,280,837 tkns saved · $19.21 saved on Opus
Ask Claude Code to set it up:
"Add astral token savings to my status line"
Claude Code will add a segment that reads ~/.code-index/_savings.json and calculates cost avoided at the Claude Opus rate ($15.00 / 1M tokens). The counter updates automatically after every ASTral tool call — no restart required.
To add it manually, read ~/.code-index/_savings.json and extract total_tokens_saved:
// Node.js snippet for a statusline hook
const f = path.join(os.homedir(), '.code-index', '_savings.json');
const total = fs.existsSync(f) ? JSON.parse(fs.readFileSync(f)).total_tokens_saved ?? 0 : 0;
const cost = (total * 15.00 / 1_000_000).toFixed(2);
if (total > 0) output += ` | ${total.toLocaleString()} tkns saved · $${cost} saved on Opus`;- Open the Agent pane > click the
...menu > MCP Servers > Manage MCP Servers - Click View raw config to open
mcp_config.json - Add the entry below, save, then restart the MCP server from the Manage MCPs pane
{
"mcpServers": {
"astral": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/ASTral/src/ASTral"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx",
"ANTHROPIC_API_KEY": "sk-ant-xxxxxxxx"
}
}
}
}index_repo: { "url": "fastapi/fastapi" }
get_repo_outline: { "repo": "fastapi/fastapi" }
get_file_tree: { "repo": "fastapi/fastapi", "path_prefix": "fastapi" }
get_file_outline: { "repo": "fastapi/fastapi", "file_path": "fastapi/main.py" }
index_folder: { "path": "/home/user/myproject" }
get_repo_outline: { "repo": "local-myproject" }
search_symbols: { "repo": "local-myproject", "query": "main" }
search_symbols: { "repo": "owner/repo", "query": "authenticate", "kind": "function" }
get_symbol: { "repo": "owner/repo", "symbol_id": "src/auth.py::authenticate#function" }
get_file_outline: { "repo": "owner/repo", "file_path": "src/auth.py" }
get_symbols: {
"repo": "owner/repo",
"symbol_ids": [
"src/auth.py::AuthHandler.login#method",
"src/auth.py::AuthHandler.logout#method"
]
}
get_symbol: {
"repo": "owner/repo",
"symbol_id": "src/main.py::process#function",
"verify": true
}
The response _meta.content_verified will be true if the source matches the stored hash and false if it has drifted.
search_text: { "repo": "owner/repo", "query": "TODO", "file_pattern": "*.py" }
Use search_text for string literals, comments, configuration values, or anything that is not a symbol name.
Using the force parameter (preferred):
index_repo: { "url": "owner/repo", "force": true }
index_folder: { "path": "/path/to/project", "force": true }
Or by invalidating the cache first:
invalidate_cache: { "repo": "owner/repo" }
index_repo: { "url": "owner/repo" }
| Tool | Purpose | Key Parameters |
|---|---|---|
index_repo |
Index GitHub repository | url, use_ai_summaries, incremental, force |
index_folder |
Index local folder | path, extra_ignore_patterns, follow_symlinks, incremental, force |
list_repos |
List all indexed repositories | — |
get_file_tree |
Browse file structure | repo, path_prefix |
get_file_outline |
Symbols in a file | repo, file_path |
get_symbol |
Full source of one symbol | repo, symbol_id, verify, context_lines |
get_symbols |
Batch retrieve symbols | repo, symbol_ids |
search_symbols |
Search symbols | repo, query, kind, language, file_pattern, max_results |
search_text |
Full-text search | repo, query, file_pattern, max_results |
get_repo_outline |
High-level overview | repo |
invalidate_cache |
Delete cached index | repo |
Symbol IDs follow the format:
{file_path}::{qualified_name}#{kind}
Examples:
src/main.py::UserService#class
src/main.py::UserService.login#method
src/utils.py::authenticate#function
config.py::MAX_RETRIES#constant
IDs are returned by get_file_outline, search_symbols, and search_text. Pass them to get_symbol or get_symbols to retrieve source code.
ASTral supports a .astralrc JSON configuration file. Place it in your project directory or home directory (~/.astralrc). Project-level values override home-level values. Environment variables override both.
{
"storage_path": "/custom/index/path",
"log_level": "DEBUG",
"max_index_files": 5000,
"extra_extensions": ".vue:javascript,.svelte:javascript",
"excluded_patterns": ["*.generated.cs", "*.Designer.cs"]
}| Variable | Description | Default |
|---|---|---|
CODE_INDEX_PATH |
Storage directory for indexes | ~/.code-index/ |
ASTRAL_LOG_LEVEL |
Log level: DEBUG, INFO, WARNING, ERROR |
WARNING |
ASTRAL_EXTRA_EXTENSIONS |
Extra extension mappings (e.g. .vue:javascript,.svelte:javascript) |
— |
ASTRAL_MAX_INDEX_FILES |
Maximum files to index | 10000 |
ASTRAL_WATCH |
Enable file watcher for auto re-indexing (true/false) |
false |
GITHUB_TOKEN |
GitHub API token for index_repo |
— |
ANTHROPIC_API_KEY |
Anthropic API key for AI summaries | — |
Set ASTRAL_WATCH=true to enable automatic background re-indexing when files change in indexed local folders. The watcher uses debounced detection (500ms) and a semaphore to prevent concurrent indexing.
Once enabled, any folder indexed via index_folder is automatically monitored. Changes to source files trigger incremental re-indexing in the background.
"Repository not found"
Check the URL format (owner/repo or full GitHub URL). For private repositories, set GITHUB_TOKEN.
"No source files found" The repository may not contain supported language files, or files may be excluded by skip patterns.
Rate limiting
Set GITHUB_TOKEN to increase GitHub API limits (5,000 requests/hour vs 60 unauthenticated).
AI summaries not working
Set ANTHROPIC_API_KEY for Claude Haiku summarization. Without it, summaries fall back to docstrings or signatures.
Stale index
Use invalidate_cache followed by index_repo or index_folder to force a clean re-index.
Encoding issues Files with invalid UTF-8 are handled safely using replacement characters.
Indexes are stored at ~/.code-index/ (override with the CODE_INDEX_PATH environment variable):
~/.code-index/
├── _savings.json # Cumulative token savings
├── owner-repo.json # Index metadata + symbols
└── owner-repo/ # Raw source files
└── src/main.py
- Start with
get_repo_outlineto quickly understand the repository structure. - Use
get_file_outlinebefore reading source to understand the API surface first. - Narrow searches using
kind,language, andfile_pattern. - Batch-retrieve related symbols with
get_symbolsinstead of repeatedget_symbolcalls. - Use
search_textwhen symbol search does not locate the needed content. - Use
verify: trueonget_symbolto detect source drift since indexing.