Agent-focused semantic mapping and language services for mixed-language codebases.
Project description
Agent Coding Language Mapper
agent-codinglanguage-mapper gives coding agents a bounded semantic view of mixed-language repositories. It maps Python, Rust, C#, Delphi, and C++ into one language-neutral index and exposes that index through a Python API, a command-line interface, Protocol 3, an LSP server, and an OpenCode skill/plugin pair. It also detects repository coding conventions, audits source against them, and produces reviewable formatting patches before any explicit write.
The mapper is designed for code investigation without sending whole files through grep, cat, or generic file-reading tools. Responses are paginated, carry stable target IDs and source citations, distinguish proven from partial relations, and preserve focus across follow-up requests.
Installation
python -m pip install agent-codinglanguage-mapper
Python 3.10 through 3.14 is supported on Windows, macOS, and Linux.
Check the installation against a repository:
codinglanguage-mapper doctor --root .
codinglanguage-mapper view --root . --layer overview --format markdown
Python API
from agent_codinglanguage_mapper import AgentRequest, CodebaseMapper, Language
with CodebaseMapper.open(".", languages="auto") as mapper:
found = mapper.request(
AgentRequest(
action="find",
query="PaymentService",
languages=(Language.PYTHON, Language.CSHARP),
)
)
item = found.result["items"][0]
detail = mapper.request(
AgentRequest(
action="inspect",
target_id=item["target_id"],
detail="body",
)
)
print(detail.to_mapping())
The public types are:
CodebaseMapperAgentRequestandAgentResponseLanguageProjectandSourceFileSymbol,Reference, andRelationProblemandSourceRangeCodingGuidelinesGuidelineProfile,GuidelineFinding,GuidelineChange, andGuidelineReport
Parser-native nodes are intentionally private. Ranges are zero-based and half-open. Rendered citations use one-based line numbers, for example src/payment.py:42.
CodebaseMapper.open() creates an outline index first. inspect, focus, and outgoing callees/uses traces load detail only for the selected source file. Incoming references/callers/used_by traces load the remaining workspace detail because their evidence can originate in any indexed file. Parsed detail and focus remain resident for the mapper session. The same optimized path is used for small and large files.
Batch consumers that only need the complete outline should use
snapshot = CodebaseMapper.index("."). This one-shot path returns the same deterministic
WorkspaceSnapshot without retaining source buffers, parser outlines, or the interactive refresh
cache after indexing. It is intended for inventory and documentation pipelines over very large
repositories.
The private session index retains each parser-native outline tree, its source buffer, a source digest, and a lightweight file fingerprint. A detail upgrade therefore queries the existing tree instead of rereading or reparsing every indexed source. When an indexed source changes during a worker session, the mapper rebuilds the outline snapshot, updates workspace_revision, clears stale detail/focus state, and invalidates old cursors before answering the next request. Parser-native nodes never appear in the public result types.
CLI
The installed command is codinglanguage-mapper.
# Layered views
codinglanguage-mapper view --root . --layer projects --format markdown
codinglanguage-mapper view --root . --layer files --language rust --format json
codinglanguage-mapper view --root . --layer symbols --query PaymentService
codinglanguage-mapper view --root . --layer implementation --query PaymentService
codinglanguage-mapper view --root . --layer references --query PaymentService
# Persistent JSON index
codinglanguage-mapper index --root . --out .mapper/index.json
# Discovery and parser diagnostics
codinglanguage-mapper doctor --root . --format json
# Detect and audit repository coding conventions
codinglanguage-mapper guidelines detect --root . --format json
codinglanguage-mapper guidelines audit --root . --format json
# Preview a deterministic patch; this never changes source files
codinglanguage-mapper guidelines format --root .
# Apply the reviewed plan atomically
codinglanguage-mapper guidelines format --root . --write
# Language Server Protocol over stdio
codinglanguage-mapper lsp --root .
# Protocol 3 NDJSON worker
codinglanguage-mapper worker --root .
Available view layers are overview, projects, languages, files, file, symbols, symbol, implementation, references, and problems.
Coding Guidelines and Formatting
The guidelines API uses the mapper's normal project discovery and language detection, so one request can audit a mixed Python, Rust, C#, Delphi, and C++ workspace. Detection is file-specific rather than one profile for the entire repository. Defaults are refined by language configuration and then by the nearest applicable .editorconfig, which has the highest precedence.
from agent_codinglanguage_mapper import CodingGuidelines
guidelines = CodingGuidelines.open(".", languages="auto")
detected = guidelines.detect()
audit = guidelines.audit()
# A stable unified diff for agent or human review; no files are changed.
patch = guidelines.patch()
print(patch)
# Mutation is rejected unless write=True is explicit.
plan = guidelines.plan()
applied = guidelines.apply(plan, write=True)
print(applied.to_mapping())
detect() reports the effective profile and its configuration sources. audit() returns exact zero-based, half-open ranges for line length, indentation, line endings, trailing whitespace, and final-newline findings. Invalid supported values and unsupported EditorConfig properties are reported as non-fixable configuration findings; affected rules retain their previous effective value. Agents can use those findings to make source-aware improvements that are outside the formatter's conservative scope. plan() records original-content hashes, the guideline-configuration revision, and the exact replacement bytes. apply() rejects stale plans after either source or configuration changes, workspace-escaping paths, and symlinks; accepted writes use a same-directory temporary file and atomic replacement.
The built-in formatter safely normalizes configured line endings, removes trailing whitespace outside protected multiline string literals, and applies the configured final-newline rule while preserving UTF-8 BOM, UTF-16, and legacy single-byte source encodings. When installed and runnable, the package delegates broader formatting to the language's established tool and validates the result with the mapper before planning it:
| Language | Detected configuration | Preferred formatter |
|---|---|---|
| Python | pyproject.toml (ruff) and .editorconfig |
Ruff, then Black |
| Rust | rustfmt.toml, .rustfmt.toml, and .editorconfig |
rustfmt |
| C# | .editorconfig common whitespace rules |
dotnet format whitespace in an isolated temporary copy |
| Delphi | RAD Studio-compatible defaults and .editorconfig |
Built-in conservative formatter |
| C++ | .clang-format, _clang-format, and .editorconfig |
clang-format |
Native formatter executables are optional and are never downloaded or installed by this package. A missing tool selects the built-in formatter. A timeout, nonzero exit, invalid output, or other native failure also falls back to the built-in formatter and emits a structured native-formatter-failed finding instead of discarding the audit. No formatter command is executed through a shell.
guidelines audit exits with status 1 when findings exist, making it suitable for CI. guidelines format without --write always prints the unified diff and leaves the workspace untouched. The only mutating CLI form is guidelines format --write.
Protocol 3
Protocol 3 is the bounded request/response contract used by the worker and OpenCode plugin.
Actions:
| Action | Purpose |
|---|---|
open |
Return projects and establish the workspace revision. |
find |
Search indexed symbols with optional project, file, and language filters. |
inspect |
Return one selected detail layer for a target. |
trace |
Follow one explicit relation from a target. |
focus |
Select a target while preserving project/file/language focus. |
problems |
Return structured discovery, syntax, and semantic problems. |
Details are summary, declaration, members, context, body, and implementations. Relations are references, callers, callees, uses, used_by, inherits, implements, and ffi.
{
"action": "trace",
"target_id": "symbol:...",
"relation": "callers",
"languages": ["csharp", "cpp"],
"max_items": 12,
"max_chars": 12000
}
Each response contains:
schema: always3workspace_revision: invalidates stale cursors after codebase changesfocus: current project, file, target, and language selectionresult: bounded result itemspage: returned/total counts, truncation state, andnext_cursorcontext: character count and approximate token count
Symbol items include a one-based citation and a role value. role is declaration, implementation, or definition; clients must use it when the language distinguishes a declaration from its implementation and must copy citation verbatim instead of recalculating it from the zero-based ranges.
Relation items include target_name and, for statically identifiable native imports, target_library. Parser-native nodes and recovery artifacts are never exposed through Protocol 3.
After focus, an unfiltered find inherits the focused project, file, and languages. An explicit file_id replaces the focused file. An explicit project or language filter starts a broader scope and clears incompatible narrower inherited filters; include file_id explicitly when that narrower restriction is still intended.
Defaults are 12 items and 12,000 characters. max_chars is capped at 40,000. Source bodies are chunked at 6,000 characters. When page.truncated is true, continue with the non-empty next_cursor; do not infer omitted items. An individual bounded summary can also contain "truncated": true while still exposing its target_id, name, language, and citation so the target can be inspected directly.
Resolution Semantics
The mapper never fabricates a relation to make a graph look complete.
| Resolution | Meaning |
|---|---|
complete |
The relation is proven inside the indexed workspace. |
sound_partial |
Returned evidence is valid, but the available static information may be incomplete. |
ambiguous |
More than one valid target remains. |
unresolved |
No defensible target can be selected. |
Same-language cross-file targets become complete only when the target is visible in the same project through an explicit Python/Rust import, C/C++ include, Delphi uses clause, or the applicable C# namespace rules. A same-name symbol elsewhere in the workspace is not sufficient.
Cross-language FFI is recognized only from explicit declarations: Rust extern, C/C++ ABI exports, C# DllImport/LibraryImport, Delphi external/exports, and statically identifiable Python ctypes/cffi usage. An import becomes complete only when its literal library identity also matches the exporter identity after conventional lib prefix and .dll/.dylib/.so suffix normalization. C/C++ exporter identity comes from explicit loadable CMake targets such as add_library(metrics SHARED metrics.cpp) or MODULE libraries; static libraries, executables, and unspecified library kinds are not treated as runtime FFI outputs. Delphi exporter identity comes from the library metrics; declaration. A source filename is never treated as proof of a native output name, and custom or unresolved outputs remain sound_partial or unresolved.
A resolved ffi trace includes complete source_symbol and target_symbol mappings. Their language, role, and citation fields provide both endpoints without a second name-based search.
Project Discovery
No environment variable is required for normal discovery. The workspace scanner respects .gitignore files at every directory level, applies each pattern relative to its directory, skips standard build/cache directories, and enforces the repository boundary. Directory symlinks are not followed, and workspace-escaping source roots are reported instead of indexed.
Supported metadata includes:
- Python
pyproject.toml,setup.cfg, and conventional/source layouts - Cargo packages and workspaces
.slnand.csproj- Delphi
.dpr,.dpk,.dproj, and.groupproj, including unit search paths, include paths, source paths, project defines, and source declarations;.dprand.dpkfiles are also indexed as source - C/C++
compile_commands.json,CMakeLists.txt, and.vcxproj
Build scripts are parsed as data and are never executed. Cargo custom library and binary paths are combined rather than treated as alternatives, and solution files resolve their referenced C# project membership. Multiple named project files in one directory keep distinct project identities; matching .dpr/.dproj pairs share one Delphi project identity. Explicit source membership has priority over broad solution or group metadata. If multiple implicit projects remain equally valid owners, the file is assigned to the synthetic workspace project and an ambiguous-project-ownership problem lists the candidate project files. Unresolved variables, missing generated files, missing project references, missing include roots, and paths outside the workspace become structured Problem records.
Language Coverage
Release-blocking fixtures and LSP assertions cover:
| Language | Supported stable range |
|---|---|
| Python | 2.7 and 3.0 through 3.14 |
| Rust | Editions 2015, 2018, 2021, and 2024 |
| C# | C# 1 through C# 14 |
| Delphi | Delphi 7 through Delphi 13 Florence |
| C++ | C++98/03 through C++23 |
Stable GNU/MSVC C++ extensions and Delphi compiler directives have dedicated fixtures. Preview, Nightly, compiler-internal, and draft syntax is Best-Effort and is reported through explicit compatibility handlers. Unknown stable syntax remains a release-blocking syntax-error; parser recovery is never silently accepted.
Run the offline formal audit:
python scripts/audit_language_matrix.py
pytest -q tests/test_language_matrix.py
Pinned external evaluations cover CPython, Rust, Roslyn, LLVM, DUnitX, and the official corpora for each pinned Tree-sitter grammar. Populate a missing corpus cache only as an explicit evaluation operation:
python scripts/evaluate_external_corpora.py --fetch --max-files 20
Every subsequent run is offline and rejects a dirty or revision-mismatched cache:
python scripts/evaluate_external_corpora.py \
--output benchmarks/results/external-corpora.json
Corpora are evaluation inputs only. They are not vendored and are never accessed at package runtime.
LSP Configuration
Start the server with:
codinglanguage-mapper lsp --root /absolute/path/to/workspace
An editor client should launch that command over stdio with the workspace directory as its root. The server advertises diagnostics, definition, hover, references, safe rename, document symbols, workspace symbols, and completion for all five languages.
Safe rename requires an exact declaration range and refuses unresolved or ambiguous references. Diagnostics retain the mapper's structured severity and source ranges.
Example generic client configuration:
{
"command": "codinglanguage-mapper",
"args": ["lsp", "--root", "/absolute/path/to/workspace"],
"transport": "stdio",
"filetypes": ["python", "rust", "cs", "pascal", "cpp"]
}
OpenCode Integration
Install the package-named skill, Markdown agent, and plugin into a repository:
codinglanguage-mapper opencode install --target .
This creates:
.agents/skills/agent-codinglanguage-mapper/SKILL.md
.opencode/agents/agent-codinglanguage-mapper.md
.opencode/plugins/codebase_map.ts
The generated agent-codinglanguage-mapper agent denies all tools by default and permits only its package-named skill, the legacy codebase_map tool, code_guidelines, three fixed phase tools (codebase_map_open, codebase_map_focus, and codebase_map_inspect_declaration), and five fixed-language find tools: codebase_map_find_python, codebase_map_find_rust, codebase_map_find_csharp, codebase_map_find_delphi, and codebase_map_find_cpp. Each fixed-language tool requires query, accepts the optional project_id, file_id, cursor, max_items, and max_chars bounds, and injects its own Protocol 3 find action and language. It defaults to at most 5 results and 4,000 characters, while callers can explicitly raise either bound when needed. The fixed open, focus, and declaration-inspect tools likewise inject their Protocol 3 action and inspect detail. These smaller schemas prevent a model from corrupting or omitting required phase fields and keep follow-up model context bounded.
All mapper tools share the same persistent worker. The plugin maps the active OpenCode directory, serializes Protocol 3 requests, applies a hard timeout, reports bounded worker stderr, restarts after failure, and preserves focus plus warm parser indexes across short idle gaps. It stops the worker when the session is deleted or after 60 seconds without another mapper request.
The installer never reads or changes opencode.json; user configuration remains
user-owned. The deprecated --write, --write-config, and --write-agent
compatibility flags are accepted, but the Markdown agent is installed by
default and those flags do not enable configuration writes.
code_guidelines exposes four actions: detect, audit, patch, and apply. The first three are read-only. apply is rejected unless its request contains write: true, so the agent must inspect a patch before it can opt into mutation.
The agent's YAML frontmatter contains its restricted permissions; no matching JSON agent block is required.
Run it with:
opencode run \
--agent agent-codinglanguage-mapper \
"Find the C# PaymentService and cite its declaration. Use the installed skill and the fixed open, C# find, focus, and declaration-inspect tools."
A typical investigation should:
- Call
codebase_map_open. - When one language is known, call its
codebase_map_find_<language>tool with a narrowqueryand optional project/file filters. Use legacycodebase_mapwithaction: findfor mixed-language searches. - Select a returned
target_idwithcodebase_map_focus. - Call
codebase_map_inspect_declarationwithout arguments for the focused declaration. Use legacycodebase_maponly when another inspect detail is required. - Use legacy
codebase_mapwithtraceonly for explicit Protocol 3 relations. - Follow
next_cursorwhen evidence is truncated.
A formatting task should first call code_guidelines with detect, then audit, then patch. The agent can either improve source-aware findings itself or apply the package plan with action: apply and write: true. It must finish with another audit; it must never use apply merely to discover what would change.
Large-Workspace Performance
The release benchmark generates one valid file above 100,000 lines for each language and a mixed workspace above 500,000 lines. On the reference Apple Silicon Mac, release budgets are:
- cold parse P95 per 100k file: 3 seconds
- mixed overview P95: 5 seconds
- warm search P95: 1.5 seconds
- inspect and focus P95: 0.5 seconds each
Reproduce the benchmark:
python scripts/benchmark_large_workspaces.py \
--lines 100000 \
--samples 5 \
--output benchmarks/results/macos-current.json
The command exits nonzero when any budget is exceeded.
Private Linux CI records and uploads the same measurements with --report-only; the Apple Silicon release budgets are enforced only on the documented reference Mac and are not applied to unrelated hosted hardware.
Offline Ornith/OpenCode Evaluation
The repository contains seven release E2Es: Python, Rust, C#, Delphi, C++, a mixed-language FFI workspace, and a coding-guidelines write workflow. They use the pinned local Ornith revision through vLLM 0.23.0 and OpenCode 1.17.18. The guidelines scenario must detect and audit the profile, inspect a patch, explicitly apply it with write: true, and finish with a clean audit. The Python scenario continues the same session through a headless OpenCode server and must inspect the focused symbol in a second turn without another find or explicit target_id, proving that the plugin preserves its warm worker. It then opens an independent session whose target-less inspect must be empty, proving that focus never crosses chat boundaries. The harness preflights the exact legacy-plus-fixed tool surface and accepts semantic evidence produced by either a fixed-language find tool or the legacy mapper. It fails if a model shard is missing, a download is attempted, an unapproved tool is called, any assistant message uses a different agent, model, or provider, a worker survives server shutdown, or required evidence is absent.
Inspect the plan without launching a model:
python scripts/run_opencode_e2e.py --plan
Verify the exact local executables, versions, model revision, and weight shards:
python scripts/run_opencode_e2e.py --verify-runtime
Run all seven scenarios and retain complete evidence:
HF_HUB_OFFLINE=1 \
TRANSFORMERS_OFFLINE=1 \
HF_DATASETS_OFFLINE=1 \
PIP_NO_INDEX=1 \
UV_OFFLINE=1 \
OPENCODE_DISABLE_AUTOUPDATE=1 \
python scripts/run_opencode_e2e.py \
--artifacts artifacts/opencode-ornith-vllm
The harness stores server logs, isolated OpenCode stdout/stderr, exported sessions, extracted tool calls, runtime metadata, and per-scenario assertions below the selected artifact directory. It probes /v1/chat/completions; a successful /v1/models response alone is not accepted as server readiness.
For a diagnostic run of one scenario, keep the same release checks and add a selector:
python scripts/run_opencode_e2e.py \
--scenario python \
--artifacts artifacts/opencode-ornith-python
The pinned Metal runtime uses VLLM_METAL_MEMORY_FRACTION=0.90. Before launch, the harness waits for at least 20.5 GB of available unified memory. The 24,576-token context keeps enough room for OpenCode's system prompt, mapped source evidence, tool-calling rounds, and up to 4,096 output tokens on the 32 GB reference Mac. OpenCode receives this context limit directly from the same runtime lock as vLLM, so client and server limits cannot drift. The harness supplies an explicit session title so OpenCode does not spend the single local inference slot generating one, and it runs the restricted agent deterministically with a bounded iteration count. The server log must show a KV-cache capacity above 24,576 tokens.
Development and Release Gates
python -m pytest -q
ruff check src tests scripts
mypy src scripts
python scripts/audit_language_matrix.py
python -m build
python -m twine check dist/*
Release artifacts must be tested from a fresh virtual environment. The wheel must contain the skill/plugin templates and must not contain, depend on, or import python-delphi-lsp.
License
Copyright is attributed to Dark Light. The package is licensed under MPL-2.0. Ported Delphi frontend files remain under the same license; python-delphi-lsp is not installed, imported, bundled as a subpackage, or modified by this project.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_codinglanguage_mapper-1.1.5.tar.gz.
File metadata
- Download URL: agent_codinglanguage_mapper-1.1.5.tar.gz
- Upload date:
- Size: 340.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
757158d2fc25c002be77e8dab95526b7752820a33de16d0cedde04f1ae94b338
|
|
| MD5 |
a40c35f8d1d4456265ad2d0fda5753cc
|
|
| BLAKE2b-256 |
551de0a81e8764207083e2acb0a561a21aeb747a3d9f240f07930c8cfe1f994d
|
File details
Details for the file agent_codinglanguage_mapper-1.1.5-py3-none-any.whl.
File metadata
- Download URL: agent_codinglanguage_mapper-1.1.5-py3-none-any.whl
- Upload date:
- Size: 173.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee47882d47dfb36b372a268066753d57aae24c418924757746515c887ada1a63
|
|
| MD5 |
39c11d111232d8237be10c67a01908f5
|
|
| BLAKE2b-256 |
357a89c22c2e18972ff60b613321c68bfa20a39ecff2359d8e0b47ff5b026854
|