Thanks for your interest in contributing! This guide covers everything you need to get started.
git clone https://github.com/ScriptedAlchemy/tracedecay.git
cd tracedecay
cargo build -p tracedecay-cli
cargo test-ciUse the Rust toolchain pinned in rust-toolchain.toml (edition 2024) and
Node.js 22+ and pnpm (the version pinned by packageManager in
package.json; an older pnpm switches to it automatically). Run
pnpm install at the repository root after cloning and whenever
pnpm-lock.yaml or a Cargo.lock changes. Besides the npm packages, it
installs every crate into .pnpm/crates, which the committed
.cargo/config.toml substitutes for crates.io and the pinned git sources, so
cargo cannot resolve dependencies until it has run. Install cargo-nextest to run the test-ci and
test-all aliases defined in .cargo/config.toml. Commands below run from the
repository root unless noted.
Two Cargo errors mean "run pnpm install at the repository root". Before any
install, Cargo reports failed to read root of directory source <repo>/.pnpm/crates/git. When Cargo.lock names a crate that is not vendored
yet, it reports no matching package named '<crate>' found with location searched: directory source '<repo>/.pnpm/crates/crates-io'.
verifyDepsBeforeRun guards only the npm packages against pnpm-lock.yaml;
pnpm install reads Cargo.lock as it is and never rewrites it or fails when
a Cargo.toml no longer matches it.
To add, remove, or bump a crate, edit the manifests by hand and refresh the lock from outside the checkout with the pinned toolchain, then vendor the result:
# <toolchain> is the channel in rust-toolchain.toml; add -p <crate> for one bump
cd / && cargo +<toolchain> update -w --manifest-path "$repo/Cargo.toml"
cd "$repo" && pnpm installInside the checkout cargo update refuses the vendored git sources and
cargo add sees only vendored crates. Do not use pnpm add crate:; from a
member directory it regenerates the whole Cargo.lock, and at the root it
fails. pnpm remove crate: is unsupported. Unused .pnpm/crates directories
stay in place after pnpm install and are inert once the lock stops naming
them. Cargo reads .cargo/config.toml from its working directory, so run
sdks/codegen cargo commands from sdks/codegen; the dashboard
contracts:generate and contracts:check scripts do this themselves.
Use your current checkout; no particular absolute path or historical PR branch is required. See AGENTS.md for checkout safety and shared-work rules.
The dashboard bundle at dashboard/app-dist/ is generated output and is
git-ignored, so a fresh clone has none. The CLI build script
(crates/tracedecay-cli/build.rs), the only crate that embeds the bundle,
builds the frontend into an immutable, digest-named copy under its own
OUT_DIR rather than embedding app-dist: pnpm run build runs when the
frontend inputs' content fingerprint changes, and the Rust build fails if pnpm
is missing or the installed packages no longer match pnpm-lock.yaml. Setting
TRACEDECAY_SKIP_DASHBOARD_BUILD stages a prebuilt dashboard/app-dist
instead, and only when TRACEDECAY_DASHBOARD_BUNDLE_SHA256 holds that
bundle's digest (print it with python3 scripts/check-dashboard-bundle.py dashboard/app-dist --print-digest); a missing or mismatched digest fails the
build. CI builds the bundle once in the dashboard-assets job and every Rust
job downloads it as an artifact. GitHub Releases ship prebuilt binaries;
workspace Cargo packages are private.
Do not assume a green baseline for the full suite: run it and read the failures; treat new failures in code you touched as yours.
Read the V2 operating-model summary before
changing storage, retrieval, or host ingestion, then follow the linked
authoritative roadmap plans. tracedecay-graph-db is the sole final Grafeo
boundary; SQLite is relational only. V2 persisted data is reset or recreated
when incompatible, do not add a prior-store reader, conversion, backfill,
shadow path, or dual write.
Tests and local validation must use isolated temporary home, profile, project,
and socket paths. Never start, install, or test a V2 daemon against an
installed master profile.
This tree map is for source orientation only. The V2 roadmap owns product precedence and acceptance.
crates/tracedecay/ Composition-root library and its integration suites
crates/tracedecay-cli/ Shipped tracedecay binary and CLI integration suites
crates/ Workspace members (code-extraction, graph-db, domain, hosts, …)
dashboard/ Embedded React dashboard
plugin/ Host bundles (Claude, Codex, Cursor, Kimi, OpenCode)
tests/ Shared fixtures, distribution suites, and cross-crate gates
docs/ Design docs and the V2 roadmap
tracedecay supports more than 50 languages. The root Cargo.toml is a virtual
workspace, not a package. crates/tracedecay-cli/Cargo.toml and
crates/tracedecay/Cargo.toml expose the language tiers;
crates/tracedecay-code-extraction/Cargo.toml owns grammar feature membership:
| Feature | Coverage |
|---|---|
lite |
Core extractors such as Rust, Go, Java, TypeScript/JS, Python, C/C++, Kotlin, C#, and Swift |
medium |
lite plus Dart, Pascal, PHP, Ruby, Bash, Protobuf, PowerShell, Nix, and VB.NET |
full (default) |
medium plus the remaining grammars selected by the extractor crate's full feature |
Build with fewer languages for faster compile times during development:
cargo build -p tracedecay-cli --no-default-features --features lite
cargo nextest run -p tracedecay-code-extraction --no-default-features --features lite- Use the task's branch, or branch from
masterfor a new contribution. Confirm the target before working on a release-channel branch. - Write tests in the owning crate. Extraction changes belong with
crates/tracedecay-code-extraction/; follow nearby inline tests or crate-local integration suites and assert on extracted nodes/edges. - Run focused tests for the affected behavior, then broaden for unresolved risk. Documentation-only edits do not require application builds. For the hosted acceptance selection:
Cargo-launched test processes are isolated from your real
cargo test-ci
~/.tracedecayprofile:.cargo/config.tomlpinsTRACEDECAY_DATA_DIRtotarget/test-profile/.tracedecay(enforced bycrates/tracedecay-cli/tests/core_cli_suite/test_profile_isolation_test.rs). Tests that need a private profile should still override it per-test, e.g. viacommon::TraceDecayStorageEnvGuardorcommon::apply_tracedecay_home_env.cargo test-alladditionally enables every optional feature; it is broader than the hosted selection. Check each suite'srequired-featuresbefore selecting it and confirm that the run executed tests rather than matching zero. - Format your code with the standard Rust toolchain:
cargo fmt cargo clippy --workspace --all-targets
For a public name or wire protocol, retain compatibility only with evidence that the external contract shipped. Persisted V2 storage has no compatibility conversion. Keep compatibility work out of storage; document the retained external boundary alongside its behavior.
The CI Clippy job runs the same command contributors should run locally before
pushing:
cargo clippy --workspace --all-targetsThis check is blocking in CI: the workflow fails if cargo clippy --workspace --all-targets exits non-zero. The composition-root lint policy in
crates/tracedecay/src/lib.rs currently denies clippy::all, clippy::unwrap_used, and
clippy::expect_used; new violations of those lints must be fixed or justified
with the narrowest practical #[allow(...)] at the affected item. Do not add a
broad allow or weaken the crate policy just to get CI green.
clippy::pedantic remains advisory. Pedantic diagnostics are emitted as
warnings and should be addressed when they point to a real maintainability issue,
but they do not block CI unless a future policy change promotes a specific lint
to deny.
There is no separate Clippy baseline file today. If a policy change intentionally promotes additional advisory lints to blocking, update the owning crate's lint policy, fix or narrowly allow the existing violations in the same change, and update this section so the contributor command and blocking/advisory split still match CI.
- Add a tree-sitter grammar dependency (or vendor it under
vendor/). - Create
crates/tracedecay-code-extraction/src/{lang}_extractor.rsimplementing theLanguageExtractortrait. - Register it in
LanguageRegistrywith a feature flag (e.g.,lang-{name}) in that crate'slib.rsandCargo.toml. - Add a test module under
crates/tracedecay-code-extraction/tests/main/and register it in that directory'smain.rs; follow nearby source and fixture patterns. - Update the feature flag tables in that crate's
Cargo.tomland this document.
When sharing traversal helpers, preserve child ordering, named versus anonymous
node handling, and direct-child versus descendant semantics. Compare against
crates/tracedecay-code-extraction/src/traversal.rs and keep language-specific
behavior local; cover the consuming extractor before and after consolidation.
Changes under plugin/ or crates/tracedecay-agent-hosts/ are covered
by a layered validation system: vendored JSON-schema checks, per-host skill
frontmatter contracts, cross-bundle sync/parity tests, and a CI
schema-validation workflow. plugin/skills/ is the shared source of truth for
bundled skills, do not fork host-specific copies. Before submitting, run:
cargo nextest run -p tracedecay --features test-helpers --test agent_suiteSee docs/PLUGIN-VALIDATION.md for the full
layer breakdown, schema refresh procedure, and how to add a skill or a new
ecosystem bundle correctly.
dashboard/src/contracts/generated.ts, dashboard/src/contracts/index.ts, and
dashboard/codegen/schemas/dashboard-contracts.schema.json are generated, not
hand-written. The Rust schemars output is authoritative: the codegen CLI
exports the schema through the tracedecay-dashboard-api library's ignored
contract_schema::tests::writes_dashboard_contract_schema test, regenerates all
three files, and compares them byte-for-byte with what is committed.
After changing any Rust type that crosses the dashboard API boundary:
cd dashboard
pnpm run contracts:generate # rewrite the generated files
pnpm run contracts:check # what CI runs; exits 1 on any driftcontracts:check is a blocking CI step in the dashboard job of ci.yml, not
an advisory one. Do not hand-edit the generated files. The check will fail and
the fix is to regenerate and commit.
The generated contract files (and the embedded Cursor extension bundle) are
marked linguist-generated in .gitattributes, so GitHub collapses them in
PR diffs and excludes them from language stats; review the Rust source of the
contract change instead.
# All extractor tests for a specific language
cargo nextest run -p tracedecay-code-extraction --test main -E 'test(/^rust::/)'
# A single test by name
cargo nextest run -p tracedecay-code-extraction --test main test_rust_file_node_is_root
# Only sync-related tests
cargo nextest run -p tracedecay --features test-helpers syncFollow conventional commit style:
fix: handle UTF-16 encoded files in sync
feat: add Dart annotation extraction
refactor: simplify reference resolver lookup
Keep the first line under 72 characters. Add a body explaining why if the change isn't obvious.
Install the local commit-msg hook once per checkout:
scripts/install-git-hooks.shCI validates commit messages with commitlint (commitlint.config.cjs):
git show --no-patch --format=%B HEAD | pnpm run --silent lint:commit --Run the same command locally (per commit) before pushing to lint every non-merge commit in a branch range. Merge commits are skipped to match CI behavior.
- Target
masterfor bug fixes and stable features. - Confirm the target branch with the maintainer for release-channel work; do not infer it from an archived plan or PR number.
- Keep PRs focused. One logical change per PR.
- Include test coverage for new behavior.
- Do not hand-edit
CHANGELOG.md; release automation generates it from conventional commit messages.
CI runs on GitHub's free hosted runners: 20 concurrent jobs for the whole account, 5 of them macOS. Every job a pull request queues is a job the integration branch waits behind, so a run spends only what its state earns:
| State | Runs |
|---|---|
| Pull request | Nothing automatically. Dispatch CI on its branch ref when the head is ready. |
CI dispatch |
Repository gates, benchmark-harness self-tests, and the Linux lane: build, clippy, feature gates, dashboard, and Linux test partitions. |
CI with run_os=true |
Adds the macOS and Windows matrices. |
CI with run_hosts=true |
Adds stock host integrations. |
CI with run_perf=true |
Adds hotpath parity. |
| Hotpath workflow dispatch | Runs the selected profile, coverage, or runtime-core suite. |
Push to master |
Everything. |
Run gh workflow run ci.yml --ref <branch> when a PR head is ready. Add
-f run_os=true, -f run_hosts=true, or -f run_perf=true only for those
lanes. Opening, pushing, labeling, and marking ready create no run at all. A
newer master push cancels the one in flight. Closing or merging a PR cancels
its remaining runs and drops its Actions caches. Nothing runs on a
timer: the packaged-crate distribution battery and the Hawk lint are
workflow_dispatch only.
Open an issue at https://github.com/ScriptedAlchemy/tracedecay/issues with:
- tracedecay version (
tracedecay --version) - OS and architecture
- Steps to reproduce
- Expected vs. actual behavior
This project follows the Contributor Covenant. Be respectful and constructive.
By contributing, you agree that your contributions will be licensed under the MIT License.