TrueCourse

AI Architecture & Code Intelligence Platform

1,500+ deterministic rules, 100 LLM rules. JavaScript, TypeScript, Python, C#.

Tests npm version License Discord

TrueCourse catches two classes of defect, through two independent tools — use either on its own or both together: - **Code defects** (`truecourse analyze`) — from the categories linters cover (unused code, style, missing types) through to ones they don't reach: circular dependencies, layer violations, dead modules, race conditions, security anti-patterns, performance footguns. Tree-sitter analysis combined with LLM review. - **Business-logic drift** (`truecourse guard`) — when the implementation no longer matches what the docs say it should do. TrueCourse curates your PRDs/ADRs/READMEs into a spec corpus, an LLM authors **scenario tests bound to each spec section** once, and `guard run` executes them deterministically — a failing scenario means that section and the code disagree. Both store their results under `.truecourse/` and surface them in a shared [dashboard](#dashboard-web-ui) for human review, with plain-text CLI output an agent can read directly.

TrueCourse Screenshot

Jump to: **[Install](#install)** · **[1. Analyze](#1-analyze--code-intelligence)** · **[2. Spec → Guard](#2-spec--guard--business-logic-drift)** · **[Dashboard](#dashboard-web-ui)** No setup step and no database: TrueCourse creates `.truecourse/` in your repo on first use and stores everything there as plain JSON files. It uses the [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) for LLM-powered work — if `claude` isn't on your PATH, deterministic analysis still runs and LLM-dependent features are skipped. --- # Install ```bash npm install -g truecourse ``` This puts the `truecourse` command on your PATH — every example below uses it. Prefer not to install globally? Run any command one-off with `npx truecourse ` instead. See [Prerequisites](#prerequisites) for Node, Claude Code, and C# requirements. --- # 1. Analyze — code intelligence Static + LLM analysis of your code: architecture, security, bugs, performance, and more. ## Quick Start ```bash cd truecourse analyze # Runs the full analysis in-process truecourse list # Show the violations it found ``` The first analyze creates `.truecourse/` and stores results as plain JSON. View them visually with [`truecourse dashboard`](#dashboard-web-ui). ## Setup The first `truecourse analyze` creates `.truecourse/` in your repo. Three files inside it are committable and travel with the repo: | File | Purpose | |---|---| | `LATEST.json` | Most recent analysis snapshot. Doubles as the baseline for `truecourse analyze --diff` and the pre-commit hook. | | `config.json` | Per-repo rule categories and LLM toggles. | | `hooks.yaml` | Pre-commit hook policy (created by `truecourse hooks install`). | Everything else (`analyses/`, `diff.json`, `history.json`, `ui-state.json`, `logs/`, `.analyze.lock`) is local-only and added to `.truecourse/.gitignore` automatically. **First time, on `main`:** ```bash truecourse analyze git add .truecourse/LATEST.json .truecourse/config.json git commit -m "add truecourse baseline" ``` **Refreshing the baseline:** re-run `truecourse analyze` after merging to `main` and commit the updated `LATEST.json`. **Don't commit `LATEST.json` from feature branches** — two PRs both updating it will conflict on a large generated JSON. ### Worktrees and fresh clones `LATEST.json` is tracked, so `git worktree add ../feat-x` and fresh clones inherit the baseline through git. `truecourse analyze --diff` and the pre-commit hook both work on the first commit in a new worktree — no per-checkout cold-start. Inside a worktree, run `truecourse analyze --diff` to see what your in-flight changes introduce relative to `main`'s committed baseline; the diff result lands in `.truecourse/diff.json` (gitignored, per-checkout). ## What it catches **Architecture** — Circular dependencies, layer violations, god modules, dead modules, tight coupling, cross-service imports **Code quality** — Magic numbers, empty catch, console.log, cognitive complexity, unused variables, redundant code, missing type hints **Security** — SQL injection, hardcoded secrets, eval usage, insecure random, XSS, path traversal, unsafe deserialization **Bugs** — Race conditions, type mismatches, mutable defaults, implicit optional, off-by-one, unchecked returns **Performance** — N+1 queries, O(n²) string concat, unnecessary allocations, missing pagination, sync I/O in async **Reliability** — Unhandled promises, resource leaks, missing timeouts, swallowed exceptions, unsafe error handling **Database** — Missing indexes, missing transactions, lazy loading in loops, raw SQL bypassing ORM, schema issues **Style** — Import ordering, naming conventions, docstring completeness, formatting preferences ### Rule coverage TrueCourse ships with **1,200+ deterministic rules** and **100 LLM rules** across 8 categories: | Category | Deterministic | LLM | Total | |---|---:|---:|---:| | Security | 150+ | 1 | 150+ | | Bugs | 250+ | 4 | 250+ | | Architecture | 30+ | 7 | 40+ | | Code Quality | 500+ | 3 | 500+ | | Performance | 50+ | 10 | 60+ | | Reliability | 40+ | 10 | 50+ | | Database | 30+ | 5 | 35+ | | Style | 50+ | — | 50+ | **Deterministic rules** run via tree-sitter AST visitors — fast, zero-cost, no API calls. **LLM rules** send source code to the configured LLM for semantic analysis — deeper but requires an LLM provider. ## Commands ```bash truecourse analyze # Analyze current repo (prompts before stashing dirty trees) truecourse analyze --stash # Pre-approve stashing pending changes (CI-friendly) truecourse analyze --no-stash # Analyze working tree as-is, no stash truecourse analyze --diff # New/resolved violations from your uncommitted changes truecourse list # Show violations from latest analysis truecourse list --all # Show all violations (no pagination) truecourse list --diff # Show diff check results truecourse add # Register repo without analyzing ``` ### Rules Configure which rule categories and LLM-powered rules are enabled per repository: ```bash # Categories truecourse rules categories # Show enabled/disabled truecourse rules categories --enable style # Enable a category truecourse rules categories --disable style # Disable a category # LLM-powered rules truecourse rules llm # Show LLM rules status truecourse rules llm --enable # Enable LLM rules truecourse rules llm --disable # Disable LLM rules # Individual rules truecourse rules list # List rules with on/off status truecourse rules list --disabled # Show only disabled rules truecourse rules disable # Disable a single rule truecourse rules enable # Re-enable a single rule truecourse rules reset [ruleKey] # Clear per-rule overrides (one or all) ``` Disabled rules are skipped at analyze time (no detection cost, no LLM calls) and any existing violations from them are hidden from the dashboard and `truecourse list` until re-enabled. The list of disabled rule keys lives in `/.truecourse/config.json` under `disabledRules`, which is intended to be committed. In the dashboard you can also toggle rules from the Rules panel (Shield icon in the top-right) or silence a noisy rule directly from any violation card via the **⋮** menu → **Disable rule for this repo**. ### Git Hooks TrueCourse can install a pre-commit hook that blocks commits introducing new violations at or above a configured severity: ```bash truecourse hooks install # Install pre-commit hook truecourse hooks uninstall # Remove pre-commit hook truecourse hooks status # Show hook status + config ``` On every commit the hook runs `truecourse analyze --diff` against the repo's last full analysis and blocks if any newly-introduced violation matches the configured block severities. **Commits will take as long as a full diff analysis** — on large repos that can be tens of seconds per commit. `truecourse hooks install` warns you and requires confirmation before writing the hook. The hook diffs against `.truecourse/LATEST.json`, so you need a committed baseline first — see [Setup](#setup). Without it the hook has nothing to diff against. **Bypass:** `git commit --no-verify` (standard git). **Configuration** — `hooks install` seeds `/.truecourse/hooks.yaml` with starter defaults; commit the file so your team shares one policy. The hook reads only from this file — if you delete it, the hook warns and passes every commit (no hidden code-level defaults). Current shape: ```yaml pre-commit: block-on: [critical, high] # severities. Valid: info|low|medium|high|critical llm: false # run LLM rules on every commit (tokens per commit) ``` --- # 2. Spec → Guard — business-logic drift TrueCourse builds a curated spec corpus from your docs, then **guards** it: an LLM authors declarative scenario tests bound to each spec section once, and running them is fully deterministic — no model in the verification loop. A failing scenario means "this section and the code disagree" (a drift or a bug — the developer's call). This is a separate pipeline from `analyze`: it answers a different question, has different prerequisites (it reads your docs), and runs on a different time scale. > **Prerequisite:** the spec scan and guard generator shell out to the Claude Code CLI (`claude -p`). Install Claude Code and sign in once before running `spec scan` or `guard generate`. `guard run` needs neither — it's deterministic. ## Quick Start ```bash cd truecourse spec scan # Curate docs → corpus (areas + overlap flags) truecourse spec conflicts list # Review flagged overlaps (resolve with `spec conflicts resolve`) truecourse guard generate # Author scenario tests from spec sections (classify → generate → birth-validate) truecourse guard run # Run the committed scenarios; exits non-zero on any drift (CI gate) ``` Resolve conflicts and review section coverage, scenarios, and run results visually in the [dashboard](#dashboard-web-ui)'s Guard section, or drive every step from the CLI. > Like `analyze`, the spec → guard track requires a **git repository** — TrueCourse's baselines are commit-anchored (committable `LATEST.json`, diff vs HEAD). On a non-git folder these commands stop with a clear message and the dashboard hides their actions. ## How it works Stages run in order, each producing committable artifacts the next consumes: **1. Spec consolidation** — Walks every `.md` file in the repo (PRDs, ADRs, RFCs, READMEs, design notes; `.truecourse/`, `node_modules/`, `.git/` etc. are skipped). An LLM relevance filter drops obvious non-spec material (task lists, research logs, AI agent prompts). For the docs that remain, an LLM tags each into **areas** (`product/concern`) and flags within-area **overlaps** where two docs may disagree. Output: `.truecourse/specs/corpus.json` (the curated corpus every downstream stage consumes — kept docs + area tags, docs grouped by area, overlap flags, and the relevance-dropped docs; committable) and `.truecourse/specs/decisions.json` (the user's resolutions: `manualAreas`, `manualIncludes`, `manualExcludes`, and conflict verdicts — committable). Only genuine within-area **disagreements** flag as overlaps — docs that agree never surface. You resolve them in the dashboard's Guard → Coverage tab or via `spec conflicts` (pick a side or dismiss). **2. Guard generation** (`truecourse guard generate`) — Splits each kept doc into sections and, per section: **classifies** whether the section makes a claim a driver can assert (today's driver runs your project's CLI; a non-testable verdict carries a one-sentence reason and surfaces as a visible coverage gap), **authors** one or more declarative YAML scenarios from the section's claim plus the code, and **birth-validates** each one by running it immediately — a scenario that fails at birth is reported as a finding (the spec and the code already disagree) instead of being silently committed. Output, all committable: `.truecourse/scenarios//*.yaml` (the scenarios), `scenarios/recipe.json` (how to build/prepare the repo for a run), and `scenarios/manifest.json` (section ↔ scenario bindings + section fingerprints, so re-generates only touch changed sections). **3. Guard run** (`truecourse guard run`) — Fully deterministic: builds the repo via the recipe, executes every committed scenario, and writes the run to `.truecourse/guard/` (per-run snapshots, `LATEST.json`, per-failure evidence transcripts). Exits non-zero on any drift, so it drops straight into CI. No LLM, no API key, no `claude` binary. The section ↔ scenario binding is **bidirectional**: code changed → its scenarios fail (code-side drift); a spec section edited → its scenarios go stale (spec-side drift). The spec document itself becomes the coverage UI — every section visibly carries its proof and its status. ## What it catches Any documented behavior a scenario can drive and assert (today through your project's CLI; api/web/tui drivers are planned): wrong responses and exit codes, missing or mistyped output fields, illegal state transitions, bypassed validation and auth rules, silently-dropped side effects, formulas producing wrong results — plus the reverse direction: spec sections whose scenarios went stale because the docs changed out from under them. ## Setup The spec, the scenarios, and a guard baseline are committable so they travel with the repo; everything else is local-only. Per-repo layout under `.truecourse/`: ``` .truecourse/ ├── specs/ ← curated corpus (committable) │ ├── corpus.json ← kept docs + area tags, docs-by-area, overlap flags, dropped docs │ └── decisions.json ← user resolutions: conflict verdicts + manual areas + manual includes/excludes ├── scenarios/ ← the guard scenario corpus (committable) │ ├── recipe.json ← how to build/prepare the repo for a run │ ├── manifest.json ← section ↔ scenario bindings + section fingerprints │ └── /*.yaml ← the scenario tests ├── guard/ ← guard run store (mirrors analyze; `truecourse guard run`) │ ├── runs/ ← per-run snapshots (gitignored) │ ├── LATEST.json ← current run state (committable) │ ├── history.json ← per-run summaries (gitignored) │ ├── evidence// ← per-failure transcripts (gitignored) │ └── result.json ← last `guard generate` summary (gitignored) └── .cache/ ← LLM caches (gitignored) ``` Like analyze, `guard/LATEST.json` is the committable baseline — commit it after merging to `main` (re-run `truecourse guard run`, commit the result), not from feature branches. ### The recipe — `scenarios/recipe.json` The recipe tells guard how to build your repo and what binary the scenarios exercise: ```json { "install": "pnpm install --frozen-lockfile", "build": "pnpm turbo build --filter=...{./tools/cli}", "entry": ["node", "tools/cli/dist/index.js"], "env": { "MY_FLAG": "1" } } ``` - `install` *(optional)* — one shell command, run in the repo root before every build, to fetch dependencies (e.g. `npm ci`). Needed wherever the tree is a fresh checkout with no `node_modules`; omit it when the build needs no dependency fetch. - `build` — one shell command, run in the repo root before scenarios execute. - `entry` — the entrypoint argv; each scenario's command is appended to it. Repo-relative. - `env` *(optional)* — extra environment variables for every scenario run. It's discovered by the LLM **once**, on your first `guard generate`, and never touched again — **the file is yours to edit**: an existing `recipe.json` always wins, and it's committed so the whole team runs the same preparation. Edit it when the discovered command isn't what you want — for example, if your build tool's cache can serve stale output across branch switches, harden the build (`turbo build --force …`, or a clean step) at the cost of slower runs. Recipe edits change the recipe fingerprint, so the dashboard flags runs made under an older recipe. ## Commands ```bash # Spec consolidation (docs → curated corpus) truecourse spec scan # Curate docs into corpus.json (areas + overlap flags) truecourse spec status # Summary: docs, areas, open vs resolved overlaps # Conflict resolution — flagged within-area overlaps # (agent-friendly; also available in the dashboard Spec tab) truecourse spec conflicts list # List flagged within-area overlaps truecourse spec conflicts show # An area's overlapping docs with prose excerpts truecourse spec conflicts resolve \ # Pick a side or dismiss a detector false-positive --right | --dismiss [--note ] truecourse spec docs list # List the kept (corpus) docs + area tags truecourse spec docs skipped # Docs the relevance filter excluded truecourse spec docs include # Force-include a skipped doc (re-scans) truecourse spec docs uninclude # Remove a force-include override truecourse spec docs exclude # Force-exclude a kept doc (re-scans) truecourse spec docs unexclude # Remove a force-exclude override # Guard — spec-section-bound scenario tests (author once, run deterministically) truecourse guard generate # Author scenarios from spec sections (classify → generate → birth-validate) truecourse guard run # Build via the recipe + run committed scenarios; exits non-zero on any drift (CI gate) truecourse guard run --scenario # Run a single scenario truecourse guard run --verbose # List every scenario result (one ✓ line per pass; default shows failures only) truecourse guard status # Compact summary: section coverage, last run, last generate (LLM-free, no re-run) truecourse guard drifts # List the latest run's non-pass scenarios, most severe first (paginated; --all / --offset / --json) ``` --- # Dashboard (web UI) One web UI for both capabilities — browse code findings and business-logic drift side by side, with the architecture graph, analytics, and the spec-curation + guard workflow. ```bash truecourse dashboard # Start + open the dashboard truecourse dashboard --reconfigure # Re-prompt for console vs background service mode truecourse dashboard stop # Stop the dashboard truecourse dashboard status # Show dashboard status truecourse dashboard logs # Tail dashboard logs (service mode only) truecourse dashboard uninstall # Remove the background service ``` - **Code Analysis** — architecture graph, violations list, severity/category analytics, code hotspots, trend over time; toggle rules and silence noisy ones inline. - **Guard** — Coverage shows each spec doc's sections with their scenario coverage and walks you through resolving spec conflicts (pick / write custom / mark superseded / include skipped doc); Scenarios lists the committed scenario corpus with the recipe and last-generate summary; Runs shows each run's drifts with per-failure evidence. --- # Common ## Claude Code Skills TrueCourse includes [Claude Code skills](https://docs.anthropic.com/en/docs/claude-code/skills) for conversational analysis from within Claude Code. The first `truecourse analyze` (or `truecourse add`) in a fresh repo asks whether to install skills into `.claude/skills/truecourse/`. Re-runs skip the prompt if skills are already present. Pass `--install-skills` / `--no-skills` to bypass the prompt explicitly. | Skill | What it does | |---|---| | `/truecourse-analyze` | Runs analysis or diff check, summarizes results | | `/truecourse-list` | Shows full violation details | | `/truecourse-fix` | Lists fixable violations, applies changes | | `/truecourse-hooks` | Installs, configures, or removes the pre-commit hook | ## Language Support | Language | Status | |---|---| | JavaScript / TypeScript | Supported | | Python | Supported | | C# | Supported * | | Go | Planned | | Rust | Planned | | PHP | Planned | \* Analyzing C# requires the .NET 8 SDK — its **semantic** rules run in a Roslyn host (build-required; analysis fails fast without it). See [Prerequisites](#prerequisites). ## Prerequisites - Node.js >= 20 - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI on your PATH — optional. The default `cli` transport spawns it for LLM-powered work; deterministic rules and the `agent` transport (below) don't need it. - [.NET 8 SDK](https://dotnet.microsoft.com/download) — **required to analyze C#** (not needed for other languages). C#'s semantic rules run in a Roslyn host you build once (`dotnet build -c Release tools/csharp-roslyn-host`, or point `TRUECOURSE_ROSLYN_HOST` at a prebuilt binary). Analyzing a repo that contains C# without the host **fails fast** with a build-the-host message — there is deliberately no tree-sitter-only fallback, since a silent half-analysis is worse than a clear error. ## LLM transport (`--llm-transport`) Every LLM-powered step — `analyze`'s LLM rules, and the whole Spec → Guard pipeline (`spec scan`, `guard generate`) — reaches the model through a pluggable **transport**, chosen with `--llm-transport`: | Mode | How it reaches the model | Needs | |---|---|---| | **`cli`** *(default)* | spawns `claude -p …` per call | the `claude` binary on PATH, signed in. No API key. | | **`agent`** | a **filesystem mailbox** under `--io ` | nothing — no `claude` binary, no API key | In **`agent`** mode the tool doesn't call the model itself: for each prompt it writes `requests/.json` (`{ stage, system, user, schema, … }`) into the `--io` directory and waits for a matching `responses/.json` (`{ text }`). An **orchestrating agent that is itself an LLM** — e.g. a [Claude Code routine](https://code.claude.com/docs/en/routines) — watches that directory and answers each prompt. This lets guard generation and `analyze`'s LLM rules run **inside a headless cloud session with no `claude` binary and no API key**. ```bash # default: spawn the claude CLI truecourse analyze --llm truecourse guard generate # agent transport: the tool parks prompts in ./io and an external agent answers them truecourse analyze --llm --llm-transport agent --io ./io truecourse spec scan --llm-transport agent --io ./io truecourse guard generate --llm-transport agent --io ./io ``` Accepted by: `analyze`, `spec scan`, `guard generate`. (On `analyze`, `--llm` / `--no-llm` is a *separate* flag — it decides **whether** LLM rules run; `--llm-transport` decides **how** to reach the model.) Both modes send identical prompts and parse identical schema-validated JSON — only the delivery differs. ## Configuration TrueCourse talks to Claude Code via the `claude` CLI. You can tune how that interaction behaves — which binary to invoke, which model to pass, timeouts, retries, and how many `claude` processes to run in parallel — through environment variables. For packaged installs (`npx truecourse` or `npm install -g truecourse`), the simplest place to set them is `~/.truecourse/.env`. The file is loaded automatically on every invocation: ``` CLAUDE_CODE_BINARY=claude # override the `claude` binary on PATH (CLAUDE_CODE_BIN also accepted) CLAUDE_CODE_MODEL= # Claude Code --model flag (empty = default) CLAUDE_CODE_TIMEOUT_MS=120000 # per-call timeout (ms) CLAUDE_CODE_MAX_RETRIES=2 # retry attempts on parse/validation failure CLAUDE_CODE_MAX_CONCURRENCY=10 # max concurrent `claude` processes per run ``` Every command that uses Claude (`analyze` with LLM rules, `spec scan`, `guard generate`) runs a quick up-front preflight: it makes one tiny `claude` call to confirm the CLI is installed and logged in, and aborts with the CLI's own error message if not — so an expired login is caught immediately instead of failing every extraction subprocess at the end of a long run. `CLAUDE_CODE_BINARY` is the canonical way to point at a non-default binary; `CLAUDE_CODE_BIN` is honored as a legacy alias. **`CLAUDE_CODE_MAX_CONCURRENCY`** caps how many Claude CLI processes TrueCourse spawns in parallel during a single run. Default `10`. Raise it on CI runners with spare headroom; lower it on resource-constrained machines (e.g. 8 GB laptops, shared VMs) to avoid OOM on large repos. Must be a positive integer. For a one-off override, prefix the command: ```bash CLAUDE_CODE_MAX_CONCURRENCY=2 truecourse analyze ``` ### Per-stage model selection Each LLM-powered pipeline stage resolves its model independently, so you can run cheap stages on Haiku and reserve Opus for scenario generation. Resolution precedence: `TRUECOURSE_MODEL_` (per-stage) › `TRUECOURSE_MODEL` (global) › `.truecourse/config.json` (`llm.stages.`) › the built-in default. `truecourse config llm` prints the effective model + source for every stage. | stage | env override | default | |---|---|---| | doc relevance keep/drop | `TRUECOURSE_MODEL_SPEC_RELEVANCE` | haiku | | area tagging | `TRUECOURSE_MODEL_SPEC_AREA_TAG` | sonnet | | overlap flagging | `TRUECOURSE_MODEL_SPEC_OVERLAP` | haiku | | guard section classify/extract | `TRUECOURSE_MODEL_GUARD_EXTRACT` | sonnet | | guard scenario generate | `TRUECOURSE_MODEL_GUARD_GENERATE` | opus | | guard recipe derivation | `TRUECOURSE_MODEL_GUARD_RECIPE` | sonnet | `TRUECOURSE_FALLBACK_MODEL` sets the `--fallback-model` used when the primary is overloaded. `TRUECOURSE_MAX_CONCURRENCY` caps concurrent LLM calls across every stage (default `min(cpus, 4)`). `TRUECOURSE_LLM_TIMEOUT_SCALE` multiplies every stage's per-call timeout by a float (default `1`); a slow model or proxy that trips the built-in ceilings can widen them all with one knob — e.g. `TRUECOURSE_LLM_TIMEOUT_SCALE=3` for a slow proxy. `TRUECOURSE_LLM_LOG` / `TRUECOURSE_LLM_DUMP` enable per-call logging. ### Excluding files from analysis TrueCourse honors `.gitignore` automatically (including nested `.gitignore` files, `.git/info/exclude`, and your configured global excludes file). For paths you want tracked in git but not analyzed — generated code, vendored snapshots, large fixtures — add a `.truecourseignore` at the repo root. Same syntax as `.gitignore`: ``` # generated src/generated/ # vendored third_party/ # specific files scripts/ingest-epub.js ``` Patterns are anchored to the file's location, so `src/generated/` matches the top-level directory only; use `**/generated/` to match at any depth. ## Telemetry TrueCourse collects anonymous usage data to improve the product — one event per command (`analyze`, `spec_scan`), each carrying only coarse, bucketed counts (file/finding *ranges*, duration range), the surface (CLI vs dashboard), OS, and tool version. No source code, file paths, identities, or violation details are collected. It is automatically disabled in CI environments. ```bash truecourse telemetry status # Check telemetry status truecourse telemetry disable # Opt out of anonymous telemetry truecourse telemetry enable # Opt back in ``` Or set `TRUECOURSE_TELEMETRY=0` to opt out. ## Development ```bash git clone https://github.com/truecourse-ai/truecourse.git cd truecourse pnpm install pnpm build # Build all packages — required before the first `pnpm test` (tests resolve workspace packages from their dist/) dotnet build -c Release tools/csharp-roslyn-host # One-time, needs the .NET 8 SDK — see note below pnpm dev # Start dashboard at http://localhost:3000 (server on :3001, Vite on :3000) pnpm test # Run tests ``` `pnpm dev` expects a `.truecourse/` folder at the repo root — created automatically on the first `truecourse analyze` against the repo (or simply `mkdir -p .truecourse`). The full test suite requires the C# Roslyn host to be built (same requirement as [analyzing C#](#prerequisites)): the C# e2e test fails without it, and the Roslyn semantic-rule tests silently skip. CI builds it before running tests (`.github/workflows/test.yml`); do the same locally, once per checkout/worktree. ## Community Join the [TrueCourse Discord](https://discord.gg/TanxB63arz) to ask questions, share feedback, and follow what's shipping. ## Contact Questions, feedback, or security reports: **Mushegh Gevorgyan** — [mushegh@truecourse.dev](mailto:mushegh@truecourse.dev). ## License MIT