LAO — Local AI Orchestrator
Local preflight for cloud AI coding agents.
Your machine gathers evidence. Claude decides.
The Problem
Every time you run Claude Code, Cursor, or Codex on a task, the agent either:
- Gets the entire repo dumped into context (expensive, noisy)
- Has to guess which files are relevant (misses things, wastes tokens)
- Sees your
.envfiles and secrets (dangerous)
LAO solves this locally — before anything reaches the cloud.
What LAO Does
lao prep "fix failing auth test" --repo ./my-repo
In under 2 seconds, locally:
- Scans the repo with ripgrep
- Scores files by relevance (keyword match, import graph, path match, stacktrace parsing)
- Blocks secrets and
.envfiles from leaving your machine - Builds a token-optimized evidence pack for the agent
Result: Claude gets 1.7k tokens of the right context instead of 72k tokens of everything.
Quick Start
# Install
pip install lao
# or: pipx install lao
# Initialize in your repo
cd your-repo
lao init
# Prepare context for a task
lao prep "fix the failing auth session test"
# Output goes to .lao/context-pack.md
# Copy to Claude: cat .lao/context-pack.md | pbcopy
Optional but recommended:
# ripgrep — 10-100x faster search
brew install ripgrep # macOS
apt install ripgrep # Linux
# gitleaks — comprehensive secret scanning
brew install gitleaks # macOS
Example Output
lao prep "fix failing auth session test" --output compact
TASK: fix failing auth session test
TYPE:bug_diagnosis DIFFICULTY:cloud_recommended CONFIDENCE:70%
REPO:nextjs/typescript FILES:61 SELECTED:6
TOKENS:1.7k (raw:72k saved:98%)
BLOCKED:.env.local
=== EVIDENCE ===
--- src/auth/session.ts [keyword:15 path:12 error:10] ---
# L38-82
```ts
export function getSession(sessionId: string): Session | null {
const session = sessionStore.get(sessionId)
if (!session) return null
const now = Math.floor(Date.now() / 1000)
// BUG: should be <= not <
if (session.expiresAt < now) {
sessionStore.delete(sessionId)
return null
}
return session
}
--- tests/auth/session.test.ts [keyword:15 path:12 test:4] ---
L28-55
it('returns null for expired session', () => {
vi.setSystemTime(new Date(Date.now() + 3601 * 1000))
const result = getSession(session.sessionId)
expect(result).toBeNull() // FAILS
})
SEND_TO:claude-sonnet
---
## Commands
| Command | Description |
|---------|-------------|
| `lao init` | Initialize lao in current repo |
| `lao prep "task"` | Prepare evidence pack for a task |
| `lao map` | Generate `.ai/` repo infrastructure |
| `lao mcp start` | Start MCP server (for Claude Code/Cursor) |
| `lao mcp config` | Show MCP configuration snippets |
| `lao check` | Check tool availability |
| `lao stats` | Show last run statistics |
| `lao show` | Show last context pack |
### `lao prep` options
```bash
lao prep "task" [options]
--repo, -r PATH Repo path (default: current directory)
--context, -c TEXT Extra context (paste error output, stacktrace)
--output, -o FORMAT markdown (default) | compact | json
--no-cloud Disable cloud routing recommendation
--verbose, -v Debug logging
Output formats
# Markdown file (default) — for manual copy/paste
lao prep "fix auth bug"
# Compact — token-efficient, for piping to agents
lao prep "fix auth bug" --output compact
# JSON — structured, for tooling
lao prep "fix auth bug" --output json
MCP Integration
LAO exposes three MCP tools so Claude Code, Cursor, and any MCP-compatible agent can call it directly.
Claude Code Setup
Add to .claude/settings.json in your repo:
{
"mcpServers": {
"lao": {
"command": "uv",
"args": ["run", "lao", "mcp", "start"],
"cwd": "/path/to/lao"
}
}
}
Or run lao mcp config to get the exact snippet for your environment.
Available MCP Tools
| Tool | Description |
|---|---|
lao_prep(task, repo_path?, extra_context?, output_format?) |
Prepare evidence pack |
lao_map(repo_path?, force?) |
Generate .ai/ infrastructure |
lao_status(repo_path?) |
Show last run stats |
Cursor Setup
Add to .cursor/mcp.json:
{
"mcpServers": {
"lao": {
"command": "uv",
"args": ["run", "lao", "mcp", "start"]
}
}
}
Codex / Other Agents
# Pipe compact output directly
lao prep "fix auth bug" --output compact | your-agent-cli
.ai/ Repo Infrastructure
lao map generates a .ai/ directory that makes your repo permanently agent-ready.
lao map
Creates:
.ai/
manifest.yaml # Stack, framework, entry points
repo-map.yaml # Module/feature → files mapping
test-map.yaml # Source file → test file mapping
risk-zones.yaml # Sensitive paths and why
agent-rules.md # Rules for AI agents (editable)
Commit .ai/ to git. Every agent that works in the repo benefits immediately.
Example manifest.yaml
repo:
name: my-app
framework: nextjs
primary_language: typescript
test_runner: vitest
package_manager: pnpm
entry_points:
- path: src/app/layout.tsx
type: application
- path: src/cli/index.ts
type: cli
ai_hints:
test_command: npx vitest run
install_command: pnpm install
Example agent-rules.md
# Agent Rules for my-app
## Always
- Run tests before declaring a fix complete
- Keep changes minimal — do not refactor unless asked
- Check .ai/risk-zones.yaml before reading sensitive files
## Never
- Send .env* files or private keys to cloud context
- Add new dependencies without asking
Security
LAO is local-first and privacy-preserving by design:
.env*files are always blocked from leaving your machine- Private keys (
*.pem,*.key,id_rsa) are always blocked - Secret scanning runs locally before any file is included
risk-zones.yamldocuments exactly which paths are sensitive and why- Nothing is sent anywhere — LAO only writes to
.lao/and.ai/locally
Default blocked patterns
.env, .env.*, .env.local, .env.production
**/*.pem, **/*.key, **/*.p12
**/id_rsa, **/id_ed25519
**/credentials*, **/*secret*, **/wallet*
Customize in .lao/config.yaml:
security:
cloud_deny:
- ".env*"
- "**/*.pem"
- "src/internal/pricing/**" # add your own
Configuration
.lao/config.yaml is created by lao init. All fields are optional.
# Token budget for context pack
limits:
max_files_in_context: 8 # Max files selected per run
max_file_tokens: 6000 # Max tokens per file
max_total_context_tokens: 30000
# Cloud routing
cloud:
enabled: true
preferred_model: claude-sonnet
# Local models (optional)
local:
embeddings_enabled: false # Enable with: lao index --with-embeddings
local_llm_enabled: false
How It Works
lao prep "fix failing auth test"
│
├── 1. Classify task → bug_diagnosis, cloud_recommended
├── 2. ripgrep search → 251 matches across 61 files
├── 3. Import graph → session.ts imported by test file (+3.0)
├── 4. Stacktrace parsing → error paths extracted from --context
├── 5. Score files → path_match + keyword_match + entry_point
├── 6. Security policy → .env.local BLOCKED
├── 7. Secret scan → 0 secrets in selected files
├── 8. Build context pack → 6 files, 1.7k tokens
└── 9. Write outputs → .lao/context-pack.md + report.json
Scoring signals
| Signal | Weight | Source |
|---|---|---|
keyword_match |
3.0/match, cap 15 | ripgrep hits in file |
path_match |
6.0/keyword | keyword stem in file path |
error_path |
10.0 | file mentioned in stacktrace |
entry_point |
8.0 / 4.0 | __init__.py, main.py etc. |
import_reference |
3.0/ref | imported by high-scoring file |
repo_map_boost |
5.0 | .ai/repo-map.yaml match |
doc_penalty |
-8.0 | README, CHANGELOG etc. |
generated_penalty |
-8.0 | auto-generated files |
Eval Results
Measured on 20 tasks across two repos (Next.js auth fixture + KMF Python library):
| Metric | Baseline | LAO v0.1 | Target |
|---|---|---|---|
| Context Recall | 60.4% | 78.3% | ≥70% |
| Safety (no secrets) | 100% | 100% | 100% |
| Tasks ≥75% recall | 40% | 50% | — |
Roadmap
| Phase | Focus | Status |
|---|---|---|
| Week 1 | lao prep end-to-end, ripgrep, security |
✅ Done |
| Week 2 | Eval harness, import graph, scorer v2, MCP | ✅ Done |
| Week 3 | Persistent index, lao index --watch |
🔜 Next |
| Phase 3 | .ai/ as community standard |
📋 Planned |
| Phase 4 | PyPI release, public alpha | 📋 Planned |
Requirements
- Python 3.11+
- uv (recommended) or pip
Optional (improves quality):
- ripgrep — faster search
- gitleaks — better secret detection
- fastmcp — MCP server (
pip install fastmcp)
GitHub Actions Integration
Add LAO to your CI pipeline with one file. Every PR gets a comment showing what would be sent to AI agents, and secrets are automatically flagged.
# .github/workflows/lao.yml
# Copy from: https://github.com/SynthexCapital/lao/blob/main/lao-github-action.yml
What the PR comment looks like:
## LAO Preflight Report
Task: fix failing auth session test
Recommended model: claude-sonnet
| Metric | Value |
|--------|-------|
| Files that would go to AI | 8 of 2,982 (99% filtered) |
| Tokens | 2,700 |
| Secrets | ✅ No secrets detected |
No secrets needed. LAO runs locally on the CI runner — your code never leaves the machine.
Set BLOCK_ON_SECRETS: "true" to automatically block PRs when secrets are detected.
License
MIT
Metadata
Release files for lao 0.1.12
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lao-0.1.12.tar.gz | 75.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lao-0.1.12-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 168.3 kB
Release files / lao-0.1.12.tar.gz
| Download URL | lao-0.1.12.tar.gz |
|---|---|
| Size | 75.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27c04c89684b05ddaea5afa0b4f25cb463dc5c7b3d641606b58459895c9b21d2
|
|
BLAKE2b-256 checksum How to use checksums |
8067de9f5cc1683b66e4c1b6126e3c1ec15bc7f8d00f2788d65fa302002cbdf6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / lao-0.1.12-py3-none-any.whl
| Download URL | lao-0.1.12-py3-none-any.whl |
|---|---|
| Size | 92.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8ff6849555e22011f6d0d6a2b2c6c14b1c1afa4577f28f9d91f73b912561187f
|
|
BLAKE2b-256 checksum How to use checksums |
afb298a8ab75e12fe92aba3ecb4c1af63b27e371f9859e75d9fc36045debad3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|