TraceLayer
Agent-native software traceability: intent, implementation, verification, provenance, and evidence as a deterministic graph.
Marker protocol · Relationships · Concepts · Policy · Hooks · Evidence · Security
TraceLayer makes the why of software traversable. One-line trace:v1 markers declare the semantic relationships that cannot be derived — which work item produced a behavior, which requirement it satisfies, which tests intend to verify it. The engine derives everything else: AST symbol attachment, Git provenance, revision fingerprints, staleness, and runtime evidence. The result is a continuously verified trace graph that agents and reviewers can query instead of loading the whole repository.
Quickstart
Install once per machine:
uv tool install tracelayer # pipx install tracelayer also works
trace install --agent claude-code --global --yes # one-time: skill + hooks for your agent
Installation vs activation
A global install is passive by default: unconfigured repositories are not
initialized or blocked. trace init activates TraceLayer for a repository.
trace setup --global --ambient explicitly opts into ambient auto-activation.
For project-local parity, run trace init && trace install --all-agents.
Once active, Ambient mode lets the user speak only prose:
you: "Build a program that scans for node_modules over 2 GB..."
agent: author a semantic ArtifactBundle (title, requirements, plan tasks)
trace task bootstrap --json '<bundle>' (internal machinery)
...compact IDs + docs/specs/{slug}.md; hooks enforce per-boundary traces
agent: "Done — WORK finalized after tests + evidence."
To activate a repository explicitly:
cd your-repo
trace init # config, invariant, skill + hooks, .mcp.json
trace index --all # builds the trace graph
trace verify --all # policy check (exit 0 = pass)
trace brief "<task>" # engineering briefing: intent, design, tests, read-first
trace orient # active work, blocks, what to read
Trace a behavior by adding one line above it:
# trace:v1 id=impl.demo satisfies=REQ-1
def do_the_thing(): ...
then trace index --all again. Staleness, evidence, hooks, and the CI gate
all build on this. Running trace outside a configured repository prints the
trace init / trace install next steps.
New artifacts use 8-character Crockford Base32 IDs: 40 bits, about 1.1e12 possible values, and roughly 4.5e-6 at 100,000 artifacts. Legacy numeric IDs remain valid.
Ambient mode in one paragraph
In an active repository, the user speaks only prose. At every
UserPromptSubmit the prompt hook resolves the request deterministically: a
strong match activates the existing work + its requirements + plan
automatically; new intent records a pending bootstrap. In reminder mode, a
mutation may proceed while its obligation is recorded; resolve that obligation
before completion, because the Stop hook blocks. trace task bootstrap --json
accepts a semantic ArtifactBundle (concise title, behavioral requirements,
distinct plan tasks). --prompt is last-resort draft scaffolding and keeps
implementation blocked until that bundle exists. A behavior-change intake
(trace task intake --kind behavior-change <WORK> --requirements REQ-x)
blocks implementation edits until the requirement text actually changes. The
authoring gate suggests qualified marker IDs (impl.<scope>.<name>), lists
candidate requirements when several are active, and auto-injects markers into
Write input (single-requirement, unambiguous) — Edits are denied with the
plan, never rewritten. On completion the Stop hook runs a safe finalizer: work
becomes done only under merge-grade policy (requirement ancestry, verifying
test, passed evidence, no stale blockers), and mutation receipts are bound to
the commit that contains the work.
How it works
flowchart LR
A[trace:v1 markers] --> B[Marker parser]
B --> C[AST symbol attachment]
C --> D[SQLite trace graph]
D --> E[Git provenance]
E --> F[Fingerprints and staleness]
F --> G[Policy evaluation]
D --> H[Query engine]
H --> I[context / why / impact / search]
G --> J[Verify gate]
J --> K[Hook engine]
K --> L[Agent context and Stop gate]
L --> M[CI merge gate]
Markers are the authoring notation; the graph is the product. Paths, line numbers, commit SHAs, and test results are derived — never written into markers — so trace identity survives refactors and evidence can never silently go stale.
Capabilities
| Area | What TraceLayer provides |
|---|---|
| Protocol | One-line versioned trace:v1 grammar, typed semantic edges, stable IDs, deterministic type inference, generated schema docs |
| Indexing | Full and changed-scope indexing, Markdown/YAML artifact extraction, fence-aware marker scanning, honest file-level degradation for unsupported languages |
| Symbols | Tree-sitter attachment for Python, TypeScript, JavaScript, Go, Rust, and Java — markers attach to symbols, never line numbers |
| Graph | SQLite materialized index with declared, structural (contains), and observed (executed) provenance; FTS5 search; bounded traversal |
| Provenance | Git-derived first-seen/last-modified history, rename tracking, changed-line ranges, dirty-tree status — no commit IDs in source |
| Staleness | Requirement/implementation fingerprints, upstream-change propagation, review states, historical evidence preservation |
| Policy | Four profiles (minimal/standard/strict/safety-critical) across five lifecycles, scoped expiring waivers, deterministic TL-rule registry |
| Query UX | context, why, impact, search, graph (tree/mermaid/DOT/JSON/JSONL), status, doctor, report pr |
| Hooks | Session start, prompt context, pre-mutation block-once guard, post-mutation guidance, batch summary, fail-closed Stop gate |
| Evidence | JUnit/Cobertura/normalized ingestion, revision binding, L0–L3 proof levels, per-test Python coverage adapter |
| Migration | CodeOps scan/plan/apply with deterministic classification, Scry detection, doctor diagnostics with rename suggestions |
| Audit | Bounded deterministic audit packages for an independent semantic reviewer — no LLM required for the engine itself |
Usage
Install
uv tool install tracelayer # PyPI; pipx install tracelayer also works
trace --help
From a local checkout: uv tool install .. From the repository directly:
uv tool install git+https://github.com/carterlasalle/tracelayer.git.
Homebrew
Formula lives in the homebrew-tap
tap (source: contrib/brew/tracelayer.rb):
brew install carterlasalle/tap/tracelayer
After each release, bump the formula (PyPI sdist URL + sha256):
contrib/brew/bump.sh # latest version on PyPI
contrib/brew/bump.sh 0.1.2 # specific version
The brew formula installs both trace and tracelayer; tracelayer never
collides with macOS /usr/bin/trace.
Note: macOS ships a built-in trace (/usr/bin/trace, Apple Instruments),
and some shells put /usr/bin ahead of ~/.local/bin — which then shadows
this project's binary. Both executables are installed, so use
tracelayer where a collision bites (tracelayer init, tracelayer verify); it has no system counterpart. Check with which trace / which tracelayer.
The first time you run trace outside a configured repository it prints
next steps: trace init to enable traceability in the current repo, or
trace install to install the skill and hooks into your agent harnesses
globally. Set TRACE_NO_HINT=1 to silence that message (e.g. in CI).
Publishing
tracelayer is published to PyPI on version tags via trusted publishing
(no tokens stored in CI). Publish a release with:
git tag v0.1.0 && git push origin v0.1.0
Manual publish from a checkout: uv build && uv publish. See
.github/workflows/release.yml for the one-time PyPI trusted-publisher
setup.
Prerequisites
- Python
3.12+ uv(dependency management is uv-only; no pip)
uv sync
uv run trace --help
Trace an existing repository:
uv run trace init --root <repo> # writes .trace/trace.toml + policy.toml
uv run trace index --root <repo> --all
uv run trace verify --root <repo> --all
uv run trace context --root <repo> <trace-id>
Run the full development baseline:
uv sync --locked --all-groups
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run pyright
uv run trace docs generate --check
uv run pytest
./scripts/ci-local.sh # full PR-gate sequence matching CI Gate
Contributor commands, mutation testing, and the CI Gate contract are in CONTRIBUTING.md and docs/ci.md.
Architecture
TraceLayer is a single Python package with deliberately narrow module boundaries:
src/tracelayer/
cli.py Typer CLI; business logic lives in modules
engine.py Indexing pipeline, verify, staleness, TraceRepository API
config.py trace.toml / policy.toml models and loading
diagnostics.py TL-rule registry; every failure carries remediation
protocol/ Marker grammar, parser, ID rules, ontology, generated schema
discovery/ File enumeration, ignore logic, monorepo scopes
artifacts/ Markdown, YAML, and generic file-level extraction
symbols/ Tree-sitter parsers and marker-to-symbol attachment
graph/ Node/edge models, SQLite store, migrations, traversal, fingerprints
git/ Provenance, history, diff-range mapping (argv-array subprocess only)
evidence/ JUnit, Cobertura, normalized JSON, freshness, proof levels
policy/ Profiles, lifecycle, waivers, deterministic rule functions
query/ context, why, impact, search
hooks/ Event handlers and file-backed session state
audit/ Bounded semantic-audit packages and external auditor adapter
migration/ CodeOps and Scry importers
Every module is independently testable; the CLI is a thin shell over the engine.
Safety model
TraceLayer sits in the coding-agent control loop, so correctness is fail-closed by construction:
- Declared claims are never displayed as proven: a
test -> exercises -> implementationclaim stays unproven until observed execution evidence exists (proof levels L0–L3). - Derived facts cannot be declared: paths, SHAs, test results, and structural/observed edges are rejected in markers.
- Ambiguity is a diagnostic, never a silent guess: detached markers, unresolved targets, and duplicate IDs are deterministic TL failures with remediation.
- Staleness preserves history: changing a requirement marks downstream review-required; it never deletes evidence.
- Repository text is untrusted data: hooks inject bounded, sanitized summaries; subprocess calls use argv arrays; no
shell=True. - Policy can weaken only deliberately: enforcement-file changes surface as TL063 warnings; waivers are scoped, owned, and expiring.
- CI and the Stop gate run the same engine as the CLI — there is no separate enforcement code path.
Documentation
| Document | Purpose |
|---|---|
| Concepts | Three truths, the trace graph, stable IDs, staleness |
| Marker protocol | Generated normative trace:v1 syntax and placement rules |
| Relationships | Generated semantic/structural/observed edge semantics |
| Policy | Profiles, lifecycles, waivers, and the TL-rule catalog |
| Hooks | Event model, block-once semantics, injection safety |
| Evidence | JUnit/Cobertura ingestion and proof levels L0–L3 |
| Migration | CodeOps scan/plan/apply workflow |
| Security | Threat model and mitigations |
| Large repositories | Incremental indexing, monorepo scopes, performance targets |
| Architecture decisions | ADR-0001 through ADR-0009 |
| CI | Independent jobs, CI Gate, mutation, release |
Installing the agent skill
The canonical skill (canonical layout: SKILL.md + README.md +
references/) lives in skills/traceability/
and is bundled with the installed package. Install it with trace install:
trace install --list # detect agents and install state
trace install --agent claude-code # project scope (.claude/skills)
trace install --agent claude-code --global --yes # ~/.claude/skills
trace install --yes # all detected agents, non-interactive
Hooks install for every agent: JSON-merged settings for claude-code
(.claude/settings.json) and codex (.codex/hooks.json); file-based hook
configs for pi (.pi/hooks.json + wrapper), omp (.omp/hook/hooks.yaml +
extension gate), and opencode (opencode.json) — each with an activation
note (e.g. pi install npm:@hsingjui/pi-hooks, /hooks-trust in omp).
The engine contract is shared across harnesses; enforcement strength is
harness-dependent (Claude Code and OMP gate Write/Edit/Bash and finalize on
Stop; Codex gates Bash only; Pi/OpenCode/Hermes are best-effort or
CI/manual — see the master spec §74). Where a harness cannot intercept,
CI merge-grade verification and trace task finish remain authoritative.
After upgrading the tool, refresh installed copies with
tracelayer update (or trace install --update). The same skill is
installable through the skills.sh ecosystem:
npx skills add carterlasalle/tracelayer --agent claude-code
For existing repositories, trace init copies the skill into
.agents/skills/traceability/ and installs hooks for every detected agent
(project scope — all files land in the repo; --no-skill opts out). The
same folder is ready for skill registries (e.g. skills.sh, anthropics/skills)
— it follows the standard layout and links references directly from
SKILL.md. Use trace install for global (user-level) agent installs.
Web UI: trace graph
trace web spawns a local web UI with a 3D force-directed graph of the
trace graph — see what connects to what, and why, through the markers:
trace web # http://127.0.0.1:8765/ (opens the browser)
trace web --port 9000 --no-open
Nodes are colored by type (requirement/decision/plan/work/implementation/
test/docs); every edge carries a proof kind — declared, structural, or
observed — and the UI uses each edge's kind for rendering. Declared marker
relationships (satisfies, verifies, exercises, work,
implements, ...) form the core graph. Click a node to inspect its upstream intent,
downstream dependents, and verification status; filter with the search box.
The server is stdlib-only and binds localhost by default.
MCP server (optional adapter)
trace mcp exposes the query surface and the verify gate as MCP tools over
stdio, so any MCP-capable agent can connect directly. It is deterministic,
local, and optional — the skill + CLI + hooks remain the canonical
interface (the spec marks MCP as never required). trace init and
trace install (project scope) register it automatically in .mcp.json
(merged, other servers preserved; trace init --no-mcp opts out).
Connect Claude Code:
claude mcp add tracelayer -- uv run tracelayer mcp
Or add a project-level .mcp.json for any MCP client (written automatically
by trace init / trace install):
{
"mcpServers": {
"tracelayer": { "command": "tracelayer", "args": ["mcp"] }
}
}
Tools: status, search, context, why, impact, verify, index.
index refreshes the graph from the repository (changed scope by default);
the rest are read-only. Results are JSON text.
Contributing
TraceLayer uses protected, squash-only pull requests with required checks. Read CONTRIBUTING.md before making changes. Run uv run trace docs generate --check when editing protocol documentation and trace verify --changed before proposing a merge — this repository traces itself.
License
Apache License 2.0 — see LICENSE.
Metadata
Release files for tracelayer 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tracelayer-0.9.0.tar.gz | 910.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tracelayer-0.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.6 MB
Release files / tracelayer-0.9.0.tar.gz
| Download URL | tracelayer-0.9.0.tar.gz |
|---|---|
| Size | 910.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bce09ce82c92668bc4077f8ebaf4f41da9dceb2d46566be5cb05791aa4773afd
|
|
BLAKE2b-256 checksum How to use checksums |
5141dbe830f52e4d0c6c7838900352d0fe2df76a38cad0147678b318f7627d7b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","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":true}
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency logRelease files / tracelayer-0.9.0-py3-none-any.whl
| Download URL | tracelayer-0.9.0-py3-none-any.whl |
|---|---|
| Size | 734.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b16b7b261b5390af47ac246ebdfa9912b0b4ba12e6d563f58a9735e0a5d061ef
|
|
BLAKE2b-256 checksum How to use checksums |
ab5cd2accc18ca2757b00dab254ed715f0068ba5e8ae6fe7c6f3d471f31cefba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","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":true}
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency log