Skip to content

Latest commit

 

History

History
325 lines (250 loc) · 14 KB

CONTRIBUTING.md

File metadata and controls

325 lines (250 loc) · 14 KB

Contributing to tracedecay

This guide covers local setup, tests, and contribution requirements.

Getting started

git clone https://github.com/ScriptedAlchemy/tracedecay.git
cd tracedecay
pnpm install
bazel build //...
bazel test //... --test_output=errors

Bazel manages the Rust toolchain and dependencies from rust-toolchain.toml, the workspace manifests, and Cargo.lock. It is the workspace build, test, check, run, benchmark, and code-generation authority locally and in CI.

Use Node.js 22+ and pnpm for JavaScript packages. The pnpm version is pinned by packageManager in package.json. Run pnpm install at the repository root after cloning and after pnpm-lock.yaml changes. Commands below run from the repository root unless noted.

To add, remove, or bump a Rust dependency, edit the manifests and refresh the lockfile and generated Bazel targets:

CARGO_BAZEL_REPIN=workspace bazel fetch --repo=@c
bazel run //scripts:gen_builds

For a targeted dependency update, use CARGO_BAZEL_REPIN=<crate> instead. Review and commit Cargo.lock and any generated target changes together. Use bazel run //scripts:gen_builds -- --check to compare generated targets without writing. The generator uses Bazel-declared Cargo and rustc matching rust-toolchain.toml. Git and network credentials remain host prerequisites.

.cargo/acquisition.toml configures Git acquisition for the generator and crate_universe. The generator passes it through Cargo's --config, which takes precedence over environment configuration. crate_universe copies it into its isolated splice, where environment configuration can override it. The splice receives only this acquisition file. The generator also discovers the checkout's .cargo/config.toml normally. Ordinary validation leaves CARGO_BAZEL_REPIN and REPIN unset. Investigate unexpected lockfile changes before repinning.

Dashboard contracts:generate and contracts:check run the //sdks/codegen:generate and //sdks/codegen:dashboard_schema Bazel targets.

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. Bazel builds the bundle as //dashboard:app_dist and passes it and its //dashboard:bundle_sha256 digest to that skip mode; release workflows ship only that embedded output. 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.

Final V2 storage

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.

Source tree reference

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

Feature flags

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 and test the generated Bazel targets during development:

bazel build //crates/tracedecay-cli:tracedecay
bazel test //crates/tracedecay-code-extraction:main --test_output=errors

Use Cargo for a feature combination only when scripts/bazel/gen_builds.py does not generate an equivalent Bazel target.

Making changes

  1. Use the task's branch, or branch from master for a new contribution. Confirm the target before working on a release-channel branch.
  2. 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.
  3. Run the owning Bazel test target, then broaden for unresolved risk. Documentation-only edits do not require application builds.
    bazel test //path/to/package:target --test_output=errors
    The rust_test wrapper sets TRACEDECAY_DATA_DIR under Bazel's TEST_TMPDIR and disables the global database. Tests that need a private profile should still override it per test with common::TraceDecayStorageEnvGuard or common::apply_tracedecay_home_env.
  4. Format Rust code, then build the workspace:
    cargo fmt
    bazel build //...

Public wire compatibility changes

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.

Clippy policy

The CI Clippy job runs the rules_rust Clippy aspect over every Bazel target with -D warnings:

bazel build --config=clippy //...

The check is blocking: the workflow fails on any Clippy warning. 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.

Adding a new language extractor

  1. Add a tree-sitter grammar dependency (or vendor it under vendor/).
  2. Create crates/tracedecay-code-extraction/src/{lang}_extractor.rs implementing the LanguageExtractor trait.
  3. Register it in LanguageRegistry with a feature flag (e.g., lang-{name}) in that crate's lib.rs and Cargo.toml.
  4. Add a test module under crates/tracedecay-code-extraction/tests/main/ and register it in that directory's main.rs; follow nearby source and fixture patterns.
  5. Update the feature flag tables in that crate's Cargo.toml and 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.

Validating plugins and skills

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:

bazel test //crates/tracedecay:agent_suite --test_output=errors

See docs/PLUGIN-VALIDATION.md for the full layer breakdown, schema refresh procedure, and how to add a skill or a new ecosystem bundle correctly.

Changing the Rust-to-dashboard wire contract

dashboard/src/contracts/types.ts, dashboard/src/contracts/decoders.ts, dashboard/src/contracts/generated.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 //sdks/codegen:dashboard_schema, which calls the tracedecay-dashboard-api library's canonical renderer. In contracts:check mode, it generates all four dashboard files and the TypeScript SDK sources, then compares every generated output byte-for-byte with the committed files.

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 drift

contracts: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.

Running specific tests

Run the generated Bazel test target that owns the behavior:

bazel test //crates/tracedecay-code-extraction:main --test_output=errors
bazel test //crates/tracedecay:agent_suite --test_output=errors

To pass a libtest filter to one target, add it after --test_arg, for example:

bazel test //crates/tracedecay-code-extraction:main \
  --test_arg=test_rust_file_node_is_root --test_output=errors

Commit messages

Follow 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.sh

CI 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.

Pull requests

  • Target master for 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.

What CI spends on a pull request

CI runs on GitHub's free hosted runners: 20 concurrent jobs for the whole account, 5 of them macOS. Pull requests and the integration branch share that capacity. CI selects jobs by run state:

State Runs
Draft pull request Repository gates and benchmark-harness self-tests.
Ready pull request, push to master, or CI dispatch Repository gates, benchmark-harness self-tests, Linux and Windows Bazel build and test, Clippy, feature gates, the shipped CLI, and the dashboard.
CI with run_os=true Adds the macOS Bazel build and test lane.
CI with run_hosts=true Adds stock host integrations.

Use gh workflow run ci.yml --ref <branch> to request an additional run; add -f run_os=true or -f run_hosts=true for the optional lanes. A newer PR head replaces its prior run. Master finishes its current snapshot and retains only the newest pending tip, so merges faster than the long pole still produce a complete green/red signal. Explicit run_os / run_hosts dispatches keep separate concurrency groups so a default push cannot cancel them while they are queued or running. Closing or merging a PR cancels its remaining runs and drops its Actions caches. Nothing runs on a timer: the packaged-crate distribution tests and the Hawk lint are workflow_dispatch only.

Reporting issues

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

Code of conduct

This project follows the Contributor Covenant. Be respectful and constructive.

License

By contributing, you agree that your contributions will be licensed under the MIT License.