Repository navigation
Releases: lousy-agents/coach
Release list
v0.11.0 — TypeScript layer rules see more imports and report what they could not place
Feature release on the v0.x local-pilot line. Headline: TypeScript layer rules now see the dynamic, type-only, and aliased imports they used to miss, and the report says when it could not place an import instead of reading as clean. Several defaults change in this release, so read "Behavior changes to check" before you upgrade a working setup. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
Project policy moves to .lousy-agents/coach.json
When you omit --project-config, coach codesignal reads .lousy-agents/coach.json from the repository, if that file is committed and valid. A committed root project.json still works and emits a deprecation diagnostic, so existing repositories keep scanning. To move it:
mkdir -p .lousy-agents && git mv project.json .lousy-agents/coach.json
On an interactive terminal, a scan that uses the root file offers to copy it, with the default answer No. --suggest-project-config now writes .lousy-agents/coach.json unless you pass --output.
Limits: the file is read at the revision being analyzed, so an uncommitted policy is ignored and a diagnostic says so. An invalid .lousy-agents/coach.json exits 2 and does not fall back to project.json.
TypeScript layer rules see more of your imports
String-literal import() and require() calls are evaluated like static imports. A paths alias in tsconfig.json is followed to the file it names. import type and export type … from are evaluated too, so a type-only import from an entity into a gateway is reported as architecture.layer_violation.
If you want type-only imports left out, set "exclude_type_only_edges": true in the policy file. This is a policy key, not a CLI flag. A finding that exists only because of type-only imports says so in its evidence: removed if exclude_type_only_edges is set.
An import whose every specifier is inline-typed (import { type X } from …) is also reported. A mixed import such as import { type A, b } from … was already reported.
Limits: a specifier built at runtime is not placed. See the next section.
The report says which imports it could not place
- An unresolved TypeScript import inside a declared layer produces
project_import_unresolved, naming the file, the specifier, and the revision. The analysis is incomplete for that edge. - External packages are counted in
project_external_imports_not_evaluated. They are not evaluated, because a path-prefix layer cannot match a package.
A dynamic load whose specifier is not a string literal is now reported. TypeScript layer rules see a call to import(expr) or require(expr) inside a declared layer, and each one produces a project_import_non_literal diagnostic. It names the file, the call, the expression (quoted and escaped), and the line. The no-findings verdict says the analysis is incomplete for those loads, so a report that lists only such a diagnostic does not read as an all-clear. --fail-on-incomplete-coverage and exit codes are unchanged.
Recognized: a bare import(...) or require(...) call. Not recognized: require.resolve(...), a method named require, createRequire(...), bundler glob imports, and indirect callee forms such as const r = require; r(x), (require as any)(x), (0, require)(x), and (require satisfies F)(x). A forbidden edge written in an unrecognized form is not detected, and no diagnostic is emitted for it. Erring toward caution, require("a" + "b"), require(...args), require?.(x), and a local function named require are reported as non-literal.
The report counts files outside every declared layer
Layer rules check only files inside a declared layer. Coach now says how many project files under the configured roots sit outside every layer.
- Text output prints one line above the verdict: "N of M project files under the configured roots sit outside every declared layer."
- JSON gains an optional
layer_membershipblock withrevision,analyzed_files, andfiles_outside_layers. Go and TypeScript schema-2 reports both carry it. - When N is greater than zero, the verdict says
forbidden_importswas evaluated only between files inside declared layers. A clean result reads "No active CodeSignal findings; forbidden_imports was evaluated only between files inside declared layers." - Single-revision and
--basescans both report it. In a diff, the whole block is omitted when the head side is not computed.
Limits: when Coach cannot compute the count (a truncated model, no declared layers, or a configured root with no analyzed file), the block is omitted. An absent block means "not computed", never zero. The count shows how much code is outside every layer. It does not show that the code is safe. --fail-on-incomplete-coverage and exit codes are unchanged, so unmapped files do not fail that flag yet.
Limits: these diagnostics say what was not evaluated. They do not prove that nothing violates a rule.
Behavior changes to check before you upgrade
- Go
--fail-on-incomplete-coveragenow exits 3 for an incomplete Go run. Before this release, an incomplete Go scan exited 0 under the flag. A CI job that relied on exit 0 may now fail. Exit codes without the flag are unchanged. - TypeScript layer findings can appear that did not before. Type-only and dynamic-import edges are now evaluated. TypeScript layer findings carry
rule_version2, so their fingerprints change once. - Overlapping layer prefixes are rejected with exit 2. For example, when one prefix is an ancestor of another and a sibling sorts between them. Before this release such a policy was accepted, and a file under both prefixes was assigned silently. Fix the prefixes so that no layer contains another.
- TypeScript anonymous callbacks have new subjects. The subject now names the enclosing function. Fingerprints and IDs for those signals change once. A line inserted above a callback keeps it
existing. - Text output and verdict wording change when files sit outside every layer. For a project policy with at least one file outside every declared layer, a new line appears above the verdict, and the verdict wording changes. Scripts that match on verdict text need an update. JSON gains one optional block.
- A report can now say the analysis is incomplete where it read clean before. A dynamic load with a computed specifier (
import(path),require(name)) inside a declared layer makes the no-findings verdict incomplete. Exit codes are unchanged. - A fresh
reduceaccumulator is no longer reported asstate.hidden_input_mutation. You will see fewer signals on that shape. - Policy discovery changed. If
.lousy-agents/coach.jsonis committed and valid, a scan with no flags reads it, and the report carries schema"2".
Try it
mise use -g github:lousy-agents/coach@v0.11.0
coach codesignal --baseline --project-config .lousy-agents/coach.json --project-language typescript --format json
coach codesignal --baseline --fail-on-incomplete-coverage
The first command runs the TypeScript layer policy and prints the new fields. The second shows the Go exit behavior: exit 3 when the scan is incomplete.
Limits and trust notes
Advisory static analysis only. A clean report is not proof of absence. A report that lists imports it could not place is not clean. Exit 0 with findings is normal: coach does not gate merges. Layer rules evaluate only files inside declared layers. TypeScript project analysis needs Node 24 or 26 and the pinned TypeScript 7.0.2 compiler.
Under the hood: the parser library was updated to v0.56.0. Parsing of unusual or edge-case syntax may differ from v0.10.0, so a finding or an absence on such code may change.
As in v0.10.0: local CLI preview, no hosted deployment, no web UI.
Binaries
GoReleaser publishes archives for macOS (darwin_arm64, darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus checksums.txt and its cosign signature bundle (checksums.txt.bundle).
Related
| Area | Issue / release |
|---|---|
| Canonical policy path | #510 |
| Go exit 3 under the flag | #576 |
| Type-only edges | #562 |
| Dynamic and alias imports | #561 |
| Non-literal imports | #568 |
| Unplaced files and the layer-membership count | #569 |
| Anonymous callback identity | #559, #566 |
| Fresh reduce accumulator | #558 |
| Overlapping layer prefixes | #560 |
| Previous release | v0.10.0 |
v0.10.0 — a read-first order for CodeSignal findings
Feature release on the v0.x local-pilot line. Headline: coach codesignal now tells you which findings to read first — two metric rules report high severity, findings rank by how far past the threshold they are, and the new --min-severity and --top flags narrow a long report to the top of that list. With neither flag, the report is unchanged apart from the additions below. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
A "read this first" order: high severity and magnitude ranking
Until now almost every finding read as medium, so a function barely over the line looked the same as one far past it.
highseverity.complexity.cognitive_complexityandcomplexity.max_nesting_depthnow reporthighwhen the measured value is at least twice the rule's threshold (cognitive complexity 30 and up, nesting depth 8 and up), andmediumfrom the threshold up.complexity.branch_densitystaysmediumat every value: its metric is a whole-file total that grows with file length, so escalating it would have madehighmean "large file".- Magnitude ranking. Within the same lifecycle group, severity, and confidence, each metric rule's findings are ordered by the metric divided by that rule's threshold, highest first. A
cognitive_complexity=116finding now sorts ahead of that rule's smaller scores instead of by file path. Findings with no numeric metric keep their path order, and different rules are never compared by magnitude. rule_idandseverityin text output. File-local finding blocks now start withrule_id:andseverity:lines, and project finding blocks printseverity:besiderule_id:, so the ranking is readable without--format json. JSON fields are unchanged.
Severity changes do not change a finding's id or fingerprint, so a finding keeps its identity and lifecycle when it escalates.
--min-severity and --top: narrow the report, not the analysis
--min-severity high|medium|advisory|lowrenders only signals at or above that level (high>medium>advisory>low).--top Nrenders only the firstNsignals in report order. When both are set, the floor applies first, then the cap.
Withheld signals are never silent. Text prints a withheld: line with the counts and a see-all command (your arguments minus the narrowing flags); JSON adds signals_withheld only when a flag was given. summary, coverage, diagnostics, and the exit status still describe the full analysis, so active_signals can be larger than the number of signals shown. Neither flag changes the exit status. An invalid value (--min-severity critical, --top 0) is a usage error, exit 2.
Two things to know. advisory ranks below medium, so --min-severity medium also withholds advisory layer findings (architecture.layer_violation, architecture.layer_bypass), and a --top cap can push them out for the same reason. And only the two complexity rules above can emit high, so --min-severity high shows only those two; security.toctou_check_then_act and state.hidden_input_mutation are always medium.
Moved files no longer read as "one fixed, one introduced"
When a --base comparison cannot establish that a Go or TypeScript file was renamed or copied (continuity_not_determined), project findings on the moved path used to read as one resolved plus one introduced. They are now reported with lifecycle: unknown, and each affected path gets a project_change_lifecycle_indeterminate diagnostic.
Diagnostics that name a path blocking a trustworthy comparison now also carry optional side (head or base) and revision JSON fields, and text output adds a matching , side: <head|base>, revision: <sha> clause. For base, revision is the merge-base, not your --base argument. A diagnostic without those fields renders as before.
Stray arguments are an error, not a silent no-op
coach codesignal takes no positional operands. Go's flag parser stops at the first non-flag token, so a stray operand used to discard every flag after it and still exit 0. It is now a usage error: usage on stderr, nothing on stdout, exit 2. This is a 0.x behavior change. If a script passed an extra token that was being ignored, remove it. Invocations with no positional argument are unchanged.
Try it
Pin the tag and narrow a baseline to its strongest findings:
mise use -g github:lousy-agents/coach@v0.10.0
coach --version
coach codesignal --baseline --min-severity medium --top 5Look for the withheld: line in the summary and the rule_id: / severity: lines in each finding. To see only the worst complexity findings, use --min-severity high; if nothing reaches high, text says No active CodeSignal findings at or above --min-severity high.
In JSON, signals_withheld records what was hidden:
coach codesignal --baseline --top 3 --format jsonCompare signals_withheld.beyond_top with the number of entries in signals.
Limits and trust notes
Advisory static analysis only. A clean report is not proof of absence, and a narrowed report is not a clean report: --min-severity and --top change what is printed, not what was analyzed.
Severity and magnitude are heuristics. high means a metric is at least twice its threshold; it is not a defect verdict. Magnitude ranking is a ratio to a rule's own threshold and means nothing across rules. max_nesting_depth is the file-wide maximum, so one deeply nested function sets it for the whole file.
In text output for project-mode reports, --top keeps the first N signals in report order, but file-local findings print before project findings, and project findings print in project_changes[] order rather than rank order.
The side and revision attribution and the unknown lifecycle for undetermined renames make an incomplete comparison visible; they do not make it complete.
As in v0.9.0: local CLI preview, no hosted deployment, no web UI. Coach stays on 0.x / pilot.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle (checksums.txt.bundle).
Related
| Area | Issue / release |
|---|---|
| Severity spread, magnitude ranking, report narrowing | #272 |
| Reject positional arguments | #273 |
Moved-file comparison and side/revision attribution |
#334 |
| CodeSignal pilot-exit gaps (in progress) | #282 |
| Previous release | v0.9.0 |
v0.9.0 — Uncommitted files are disclosed, not silently skipped
Feature release on the v0.x local-pilot line. Headline: coach codesignal now tells you when uncommitted files were not analyzed, instead of printing the same all-clear as a clean repository. What Coach analyzes is unchanged — committed HEAD only — and exit status stays 0. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
Uncommitted files are disclosed, not silently skipped
Coach has always analyzed the committed snapshot, never your working tree. Until now it did not say so: a tree with edited, staged, or brand-new Go or TypeScript files printed No active CodeSignal findings. — the same verdict as a clean checkout, for bytes Coach never read.
Now --baseline and --base both check git status and record what they skipped as diagnostics, in text and JSON:
- Supported-language files (Go, TypeScript, TSX) that are untracked, staged, modified, or unmerged each get a
worktree_changes_not_analyzeddiagnostic per category, with the count and up to five paths — for example1 modified file was not analyzed: a.go. The text verdict becomesNo active CodeSignal findings, but the analysis is incomplete: additional diagnostics were recorded. - Only other files changed (for example
notes.md): oneworktree_not_cleandiagnostic lists them, and the verdict stays the plainNo active CodeSignal findings., because nothing Coach analyzes was skipped. git statusitself fails: aworktree_status_check_faileddiagnostic records why, and you still get a report.
A clean tree produces byte-identical output to v0.8.0. Findings are unchanged either way — they still come only from committed HEAD.
--project-config scans use a separate diagnostic for uncommitted changes
In v0.8.0, a --project-config scan with uncommitted changes under a selected root, the policy file, or package or tsconfig metadata added worktree_changes_not_analyzed. That scan now adds worktree_report_reflects_committed_head instead, so worktree_changes_not_analyzed means one thing: specific supported-language files were skipped.
This is a 0.x behavior change. If a script looked for worktree_changes_not_analyzed to detect a dirty project scan, look for worktree_report_reflects_committed_head as well. A dirty supported-language file under a project root still produces worktree_changes_not_analyzed from the file-level check above.
Try it
Download the coach binary for your platform from the release assets, or pin the tag:
mise use -g github:lousy-agents/coach@v0.9.0
coach --versionIn any repository, edit a tracked Go or TypeScript file without committing, then scan:
coach codesignal --baseline
coach codesignal --base main --format jsonLook for the Diagnostics: section in text, or diagnostics[].kind values worktree_changes_not_analyzed and worktree_not_clean in JSON. Commit or stash, rerun, and the diagnostics disappear.
A project scan with uncommitted policy or source changes:
coach codesignal --baseline --project-config project.json --project-language typescript --format jsonLook for worktree_report_reflects_committed_head.
Limits and trust notes
Advisory static analysis only. A clean report is not proof of absence.
Coach still does not analyze your working tree. These diagnostics tell you what was skipped; to analyze those changes, commit them and rerun. Working-tree scanning is tracked in #168.
Exit status is 0 whether or not the tree is dirty. If a script needs to fail on skipped files, check diagnostics[].kind in the JSON report.
The report lists at most five paths per category; the count in each message is the full number.
As in v0.8.0: local CLI preview, no hosted/AWS deployment, no web UI. Coach stays on 0.x / pilot.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle. This release builds against gotreesitter v0.55.1 (up from v0.55.0), the pure-Go Tree-sitter runtime behind file-local parsing.
Related
| Area | Issue / release |
|---|---|
| Disclose uncommitted files Coach does not analyze | #265 |
| Working-tree scanning (open) | #168 |
| CodeSignal pilot-exit gaps (in progress) | #282 |
| Previous release | v0.8.0 |
v0.8.0 — TypeScript project scans show their provenance and scope
Feature release on the v0.x local-pilot line. Headline: a TypeScript --project-config scan now reports what it analyzed and what produced the report, and says plainly when a complete scan found no configured match. Without --project-config, file-local coach codesignal --baseline / --base behaves as before, except that diff mode now analyzes renamed and copied files. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
TypeScript project reports show their provenance and scope
A --project-config … --project-language typescript scan (JSON schema_version: "2") now carries two new top-level keys, and the text report renders both.
project_scopeanswers "what did this scan look at?" It carriesinclusion_rule,pattern_set, and, forhead(andbasein--basemode), therevision, each root with itscandidate_filesandanalyzed_files, plusmatched_layersandunmatched_layers. Roots are counted independently, so a nested root is reported alongside its parent rather than folded into it. In text, aProject scope:section now prints before any findings, so you read the analyzed scope before the results.project_provenanceanswers "what produced this report?" It recordslanguage,config_digest,selected_roots, theanalyzer(versioncoach-ts-project-sidecar@1, asha256:digest,protocol_version), theruntime(Nodekind/version/origin, pluscompiler_version/compiler_origin), and per-revisioncoverageformodel,bypass, andreachability. Each coverage value is one ofcomplete,incomplete,not_run, ornot_requested. Text prints it as aProject provenance:section after the coverage sections.project_provenance.package_manager(kind,version,origin) is read from the committed snapshot at the analyzed revision: thepackage.jsonpackageManagerfield (origin: package_manager_field) or a recognized lockfile (origin: lockfile). An uncommitted lockfile does not change it. Only npm, pnpm, and bun are reported. The key is omitted for yarn, for metadata that disagrees with itself, and for roots that disagree with each other.versionis the version of that executable found on yourPATH, and it is omitted when it cannot be verified.
These keys appear only on TypeScript project reports. Go --project-config reports and schema-1 reports (no --project-config) do not include them.
Any --project-config scan (Go or TypeScript) now adds a worktree_changes_not_analyzed diagnostic when you have uncommitted or untracked changes under a selected root, to the policy file, or to package-manager or tsconfig* metadata (for example package.json, a lockfile, or .npmrc). The report still describes committed HEAD. The diagnostic tells you that your working edits are not in it.
Honest verdicts and --fail-on-incomplete-coverage
When a TypeScript project scan's required coverage is complete and nothing matched, the report now says so by name. Required coverage means model is complete and bypass is complete or not_requested, on every analyzed side. Nothing matched means no active architecture.layer_violation or architecture.layer_bypass finding, and, in --base mode, no introduced, existing, or resolved project change. In that case:
- Text prints
Complete scan found no configured covered match.in place of the generic no-findings line, provided the scan also produced no file-local signals. If some paths were not analyzed, the sentence ends with, but N paths were not analyzed. - JSON adds
project_next_actions, an ordered list ofkindvalues:record_baseline(--baselineonly — keep the reported HEAD revision for a later--base <revision>comparison; Coach persists nothing),review_policy_coverage(check selected roots and matched/unmatched layers against what you meant), andinspect_diagnostics(only when the report carries diagnostics). Text prints the same list underNext actions:.
When required coverage is incomplete, project_next_actions is absent and the verdict stays No active CodeSignal findings, but the analysis is incomplete: …. Reachability gaps alone do not make a scan incomplete.
New flag: --fail-on-incomplete-coverage. With it, a TypeScript project scan (--base or --baseline) exits 3 when required project coverage is incomplete or did not run, on any analyzed side. The report is still written to stdout first and is byte-identical to the run without the flag. Without the flag, the same scan exits 0, as before. The flag has no effect on a scan without --project-config, and Go project reports carry no project_provenance coverage for it to check. It does not change --check-project, --suggest-project-config, or --prepare-compiler. In a scan, exit 3 now comes only from this flag. --prepare-compiler keeps its own separate exit 3.
Renamed and copied files are analyzed in --base mode
Diff mode used to skip git R (rename) and C (copy) paths with an unsupported_change_type diagnostic, so a renamed file's content was never analyzed. Now Coach analyzes the new path's HEAD content. Coach does not diff it against the old path, so:
- Every signal on that path is
lifecycle: unknown, notintroducedorexisting, and counts insummary.unknown_signals. - The report carries one
continuity_not_determineddiagnostic on the new path.
This is a 0.x behavior change. A check that fails only on introduced_signals > 0 will not fire on a pure git mv of a file that has signals. Treat unknown plus continuity_not_determined as incomplete, not green. Diff mode passes --find-renames (git's default 50% similarity) and --find-copies-harder to git diff --name-status, so rename and copy detection uses those settings rather than your local git config.
Statuses Coach still does not analyze (T, U, X, B) keep unsupported_change_type. JSON summary gains files_unanalyzed, the count of diagnostic paths that were never analyzed; it is omitted when zero. summary.files_with_diagnostics now counts every distinct path that has a diagnostic, including those unanalyzed ones. It used to count only analyzed paths, so the number can rise on the same range. The text all-clear line uses files_unanalyzed for its "N paths were not analyzed" clause.
Try it
Download the coach binary for your platform from the release assets, or pin the tag:
mise use -g github:lousy-agents/coach@v0.8.0
coach --versionFrom a TypeScript project with a committed policy, run a project scan and read the Project scope:, Project provenance:, and Next actions: sections:
coach codesignal --baseline --project-config project.json --project-language typescriptThe same scan as JSON — look for project_scope, project_provenance, and project_next_actions:
coach codesignal --baseline --project-config project.json --project-language typescript --format jsonMake an incomplete scan fail a script, while still getting the report:
coach codesignal --base main --project-config project.json --project-language typescript --fail-on-incomplete-coverage --format json > report.json
echo "exit: $?" # 3 when required coverage is incomplete; 0 otherwiseNo policy yet? Start read-only, as in v0.7.0:
coach codesignal --baseline --check-project --project-language typescriptOn a branch where you renamed a file with git mv, see the rename analyzed:
coach codesignal --base main --format jsonLook for "lifecycle": "unknown" on the new path and a continuity_not_determined diagnostic.
File-local analysis:
coach codesignal --baseline
coach codesignal --base mainLimits and trust notes
Advisory static analysis only. A clean report is not proof of absence. Complete scan found no configured covered match. means the policy you committed matched nothing in the files the scan covered. It does not mean the code is compliant with an intent the policy does not express. That is why review_policy_coverage is always among the next actions.
project_scope counts the files the snapshot tsconfig includes. It does not separate production from test code for TypeScript (#281), so test files inside an included root are counted and analyzed.
Coach still analyzes committed Git objects only. worktree_changes_not_analyzed reports that uncommitted edits exist. It does not analyze them.
Rename and copy continuity is not established. Renamed-file signals stay unknown until old-path comparison lands (#438).
--fail-on-incomplete-coverage is an opt-in exit code for your own scripts. Coach does not gate merges, and exit 0 does not mean a scan was complete — read project_provenance coverage for that.
Bun is not a project runtime (#354). A bun lockfile can be reported as package_manager.kind: bun, but the scan still runs on Node 24 or 26.
As in v0.7.0: local CLI preview, no hosted/AWS deployment, no web UI. Coach stays on 0.x / pilot.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle. This release builds against gotreesitter v0.55.0 (up from v0.53.0), the pure-Go Tree-sitter runtime behind file-local parsing.
Related
| Area | Issue / release |
|---|---|
| Project provenance, scope, and honest verdicts | #333 |
| Rename/copy analysis in diff mode | #264 |
| Rename/copy lifecycle continuity (open) | #438 |
| TypeScript production/test classification (open) | #281 |
| TypeScript project-analysis journey (in progres... |
v0.7.0 — guided setup when a TypeScript scan cannot proceed
Feature release on the v0.x local-pilot line. Headline: a TypeScript scan that cannot proceed now offers guided setup on a terminal, then resumes the same scan. Default file-local coach codesignal --baseline / --base is unchanged if the scan can already run. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
Guided setup when a TypeScript scan cannot proceed
On a controlling terminal, a TypeScript --project-config scan that cannot start no longer stops at a remediation line.
- Missing or uncommitted policy: Coach opens guided policy authoring. With
--format json, that exit-2document is a JSON object with"schema_version": "1"androots— not a CodeSignal report (noscope/signals/coverage). The scan cannot pass--output, so save the candidate yourself, review it, commit it at the analyzed revision, then rerun. - Committed policy, unresolved compiler: Coach names the failing check, then offers a menu of up to four choices —
project_package(the project's own install, for examplenpm ci --ignore-scripts),project_mise,global_mise, andcancel. This is a superset of standalone--prepare-compiler, which remains mise-only. A choice that would open only to report nothing to do is withheld. A gap with nothing installable never opens a prompt; stderr names why each choice was ruled out.
A mutating choice shows a preview (executable, arguments, working directory, expected on-disk changes, network use, script-suppression policy, 5-minute timeout) and needs a separate confirm / install answer. Anything else cancels. Cancel or failure exits 2 with no CodeSignal report. Success reruns full readiness and resumes the original scan only if that rerun is ready or ready_with_limits. The offer runs at most once per invocation.
--prepare-compiler still refuses a host-Node gap (node_missing / node_unsupported) without opening a menu, matching the scan offer so the two paths cannot disagree. Host Node stays a runtime boundary: Coach has no setup command for it. Supported majors remain exactly 24 and 26.
New flag: --no-interactive. A non-empty CI environment variable has the same effect. A scan then prints the same message-only remediation a piped run gets and still exits 2. --suggest-project-config (TypeScript) and --prepare-compiler refuse with exit 2 instead of prompting. Use this when a pty-allocating runner (docker run -t, ssh -t) would otherwise hang on an unanswered prompt. Redirecting stderr away from the terminal (2>run.log) hides prompts while the session still waits — pass --no-interactive if you do not intend to answer.
Without a terminal, a compiler gap whose only executable choice is project_package is not handed --prepare-compiler (that flag cannot run it). The scan appends a line telling you to rerun the same scan on a terminal.
--check-project no longer invents an unsupported-shape or package-manager gap for a monorepo whose manifests sit under an uncommitted policy. With no policy, checks.project_shape and checks.package_manager stay not_checked.
Added files count as introduced; summary.unknown_signals is now present
In --base mode, git A files are lifecycle: introduced and increment introduced_signals. They used to land as unknown. That is a 0.x behavior change for anyone who treated added-file signals as residual classification.
JSON summary now includes unknown_signals. Every signals[] entry is counted in exactly one of introduced_signals, existing_signals, resolved_signals, baseline_signals, unknown_signals. unknown is leftover classification, not "new in this diff." --baseline still marks those signals baseline.
active_signals is len(signals) after the include-resolved filter. In --base mode that total includes resolved, so it is not "problems present at HEAD." Sum introduced + existing + unknown for that (and baseline under --baseline).
Try it
Download the coach binary for your platform from the release assets, or pin the tag:
mise use -g github:lousy-agents/coach@v0.7.0From a Git checkout of a TypeScript project, start read-only:
coach codesignal --baseline --check-project --project-language typescriptOn a terminal, run a project scan. If policy or compiler is missing, answer the offer (or decline it):
coach codesignal --baseline --project-config project.json --project-language typescriptForce the unattended path even on a real TTY:
coach codesignal --baseline --project-config project.json --project-language typescript --no-interactive
CI=1 coach codesignal --baseline --project-config project.json --project-language typescriptStandalone mise compiler setup is unchanged, and still narrower than the scan offer:
coach codesignal --baseline --prepare-compiler --project-language typescriptAdded-file lifecycle on a diff:
coach codesignal --base main --format jsonLook for "lifecycle": "introduced" on A-status files and summary.unknown_signals.
File-local analysis is unchanged:
coach codesignal --baseline
coach codesignal --base mainLimits and trust notes
Advisory static analysis only. A clean report is not proof of absence. --check-project exits 0 even when there are gaps — inspect status, checks, and gaps; do not treat process status as a gate.
The scan offer is consented, interactive, and may use the network. It is not unattended. It requires a TTY unless you pass --no-interactive or CI. It can leave a partial package-manager or mise install if the chosen command fails. It does not install Node, does not make a TypeScript scan succeed on every foreign repository, and does not run unattended project-package setup. Bun is not a project runtime.
--prepare-compiler remains mise-only. Do not expect it to resolve a project_package-only gap.
As in v0.6.0: local CLI preview, no hosted/AWS deployment, no web UI. Coach stays on 0.x / pilot.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle.
Related
| Area | Issue / release |
|---|---|
| Guided scan setup offer | #330 |
| Added-file lifecycle | #262 |
| TypeScript project-analysis journey (in progress) | #280 |
| Previous release | v0.6.0 |
v0.6.0 — consented TypeScript compiler setup with --prepare-compiler
Feature release on the v0.x local-pilot line. Headline: consented TypeScript compiler setup with --prepare-compiler. Default coach codesignal scans are unchanged if you omit the flag. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
Consented compiler setup (--prepare-compiler)
When --check-project reports a missing TypeScript compiler, you can now install one through mise without leaving the CLI:
coach codesignal --baseline --prepare-compiler --project-language typescriptThis is an interactive TTY session. It refuses (exit 2, stderr only) if there is no controlling terminal. A reviewed, committed project policy is required first — if policy is not pass, Coach tells you to run guided authoring (--suggest-project-config --project-language typescript) and does not mutate anything.
Offered choices are the verified mise scopes only: mise_project and/or mise_global. There is no default. Type the exact choice name, then type install to confirm. Anything else cancels with exit 2 and no mise change.
The preview names the executable (mise), arguments (install of the pinned TypeScript tool, then mise where), a private working directory outside the repo, expected mise store changes, network use (yes — download from the npm registry), lifecycle-script suppression, and a 5-minute timeout. A successful install re-runs readiness and prints the post-install checks.compiler state on stderr. This flow never writes a CodeSignal report to stdout.
Coach does not edit mise.toml or global mise config files. A failed or partial mise install is not cleaned up.
Package-manager classification on --check-project
--check-project now fills checks.package_manager instead of leaving it not_checked. npm, pnpm, and Bun are detected from the selected root’s nearest package.json or a recognized lockfile, then classified by probing the binary on PATH (not the packageManager pin) against a frozen matrix: npm >=11 <12, pnpm >=10 <11, Bun stable >=1.0.0 <2.0.0 (no prerelease/canary/commit builds). Yarn is withheld as unsupported and is never invoked.
JSON keys you will see: checks.package_manager.state, .code, .kind, .version, .pinned_version. Gap codes include package_manager_ambiguous, package_manager_config_unverifiable, package_manager_version_unverifiable, and package_manager_version_unsupported. A rejected package-manager finding is scoped to setup: it does not fail a repository that already has a working compiler.
Unattended project-package setup (npm/pnpm/bun install from this CLI) is not a command in this cut. Bun is not a project runtime. Do not expect those to work yet.
Try it
Download the coach binary for your platform from the release assets, or pin the tag:
mise use -g github:lousy-agents/coach@v0.6.0From a Git checkout of a TypeScript project, start read-only:
coach codesignal --baseline --check-project --project-language typescript
coach codesignal --baseline --check-project --project-language typescript --format jsonIf status is needs_policy, author and commit a config (interactive TTY; writes nothing until you confirm):
coach codesignal --baseline --suggest-project-config --project-language typescriptThen, on a TTY, install a missing compiler:
coach codesignal --baseline --prepare-compiler --project-language typescript
# or, if the policy is not at project.json:
coach codesignal --baseline --prepare-compiler --project-language typescript --project-config project.jsonFile-local analysis is unchanged:
coach codesignal --baseline
coach codesignal --base mainLimits and trust notes
Advisory static analysis only. A clean report is not proof of absence. --check-project exits 0 even when there are gaps — inspect status, checks, and gaps; do not treat process status as a gate.
--prepare-compiler is consented, interactive, and network-using. It is not unattended. It requires a TTY and a committed policy. It can leave a partial mise install if mise install fails. It does not run project-package managers, does not install Node, and does not make a TypeScript scan succeed on every foreign repository.
As in v0.5.0: local CLI preview, no hosted/AWS deployment, no web UI. Coach stays on 0.x / pilot.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle.
Related
| Area | Issue / release |
|---|---|
| Consented mise compiler setup | #328 |
| TypeScript project-analysis journey (in progress) | #280 |
| Previous release | v0.5.0 |
v0.5.0 — TypeScript project analysis runs on your own compiler
Feature release on the v0.x local-pilot line. Headline: TypeScript --project-config scans now run Coach's own embedded analyzer against a TypeScript 7.0.2 compiler resolved on your machine, so the analyzed repository no longer has to carry Coach's js/semantics analyzer build. Default file-local coach codesignal --baseline / --base and Go --project-config analysis are unchanged. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
TypeScript project scans use an embedded analyzer and your installed compiler
coach codesignal --project-config <path> --project-language typescript no longer looks for js/semantics/bin/coach-ts-project-sidecar inside the analyzed repository. The analyzer ships inside the coach binary and is unpacked to a private temporary directory for each run. If you vendored Coach's analyzer into a repository to make v0.4.0 work, you can delete that copy.
The scan instead needs two things on the host:
-
Node 24 or 26 on
PATH. Any other major is refused. -
An installed TypeScript compiler whose own
package.jsonversion is exactly7.0.2, plus its matching native platform package (@typescript/typescript-<os>-<arch>, same version). Coach looks in three places, in this order, and uses the first one that supplies a supported compiler:node_modules/typescriptbeside the nearestpackage.jsonat or above each selected policy root (bounded by the repository);- an
npm:typescriptexact pin in the[tools]table of the repository'smise.toml; - your global mise config (
tools.npm:typescript).
Version ranges (
^,~,latest) never count as a compiler. What decides is the version actually installed, not the one declared.
When no supported compiler or Node can be resolved, the scan exits 2, writes nothing to stdout, and prints one stderr line that names the gap and the fit check to run. For example:
typescript_compiler_missing: run coach codesignal --baseline --check-project --project-language typescript --project-config project.json
typescript_version_conflict (apps/web@7.0.2,apps/api@5.4.0): run coach codesignal --baseline --check-project --project-language typescript --project-config project.json
Other codes on that line are typescript_version_mismatch, node_missing, and node_unsupported. The line lists root findings (<root>@<version>) for a conflict, and for a mismatch caused by a selected root's own compiler. It never prints a filesystem path.
This is a 0.x behavior change. In v0.4.0 a missing analyzer produced an incomplete report at exit 0. Now an unresolvable compiler or Node is a refusal at exit 2. An analyzer that starts and then crashes or times out (60-second budget) still yields a qualified, incomplete report at exit 0.
While it analyzes, the analyzer reads project source, tsconfig, and package metadata only from the Git snapshot of the analyzed revision, never from your worktree. It runs with its working directory set to its own private directory and PATH limited to the Node runtime's directory. Node loader options (NODE_OPTIONS) and proxy settings (HTTP(S)_PROXY) are stripped from its environment, and it does not use the network. Read-only mise probes (mise config get, mise where) run from a neutral directory with a minimal environment, so exec templates in the analyzed repository's mise.toml do not run.
--check-project now checks the compiler and the supported Node set
coach codesignal --baseline --check-project --project-language typescript used to report the compiler as not_checked. It now runs the same compiler resolution the scan uses, so a compiler pass here means the scan resolves that same compiler rather than refusing.
checks.compilerpasses withversionwhen a supported compiler is found. It fails withtypescript_compiler_missing(withexpected_version, anddetailnaming the native package when that is what's missing or version-divergent),typescript_version_mismatch(withexpected_version,found_version,supported_versions), ortypescript_version_conflict(withroot_findingswhen selected roots disagree).- A new warning,
compiler_declaration_mismatch(withdeclared_version,found_version,declaration_origin,root), appears when a manifest declares a version other than the compiler the scan will use. For example, a stale exact pin beside a supported install. It movesstatustoready_with_limitsand never becomes a gap. Coach never edits your manifests. - The supported Node majors are now exactly
24and26. A newchecks.runtimeobject (kind: "node",origin: "path",version) carries the result.checks.nodemirrors itsstate,code, andversion. Any other major is the gapnode_unsupported. Ifnode --versionfails, times out, or prints something unparsable, the gap isnode_unverifiable, anddetailsays why. next_actionsentries now carry structured fields.install_supported_runtimehasruntime_kindandsupported: ["24","26"], plusfound_versionfor an unsupported major.repair_runtime_probehasdetail.prepare_compilerhassupported: ["7.0.2"]andfound_version. Coach does not run any of these for you in this release.
This is also a 0.x contract change. The node_below_minimum gap and the node_untested warning are gone. A Node 25 or 27 host that previously passed, or passed with a warning, is now node_unsupported. checks.package_manager is still not_checked.
@lousy-agents/coach-semantics now declares engines.node: "^24 || ^26" to match.
Guided TypeScript policy authoring (--suggest-project-config --project-language typescript)
coach codesignal --baseline --suggest-project-config --project-language typescript opens an interactive session for writing a TypeScript project.json.
It lists the TypeScript roots (directories with a tsconfig.json) it found in committed HEAD, plus directories with a package.json but no tsconfig.json. Discovery reads only file names in the Git snapshot. It does not need a compiler, and it ignores your worktree. You then choose, in order:
- roots, by list number or repository-relative path (at least one, at most 256);
- named layers, each with one or more path prefixes (unique and non-overlapping across layers);
- forbidden layer-import pairs;
- an optional
required_layer.
Coach suggests roots but never preselects them, and it never infers, proposes, or recommends layers. An invalid answer is explained, and you can retry or cancel. Before anything is written, Coach shows the full candidate and a coverage preview: which discovered directories each layer matches, and which match no layer. Only typing approve writes it. Anything else cancels.
The approved schema-1 document goes to stdout, with the prompts on stderr, so you can redirect stdout to a file. With --output <path>, it's written create-only to that repository-relative path instead, and an existing file is never overwritten. The candidate is not in use until you review it, commit it, and pass it to --project-config.
Exit codes: 0 when approved and written; 2 when cancelled, not approved, invalid, --output already exists, or discovery ran out of budget; 3 when the revision or snapshot cannot be read. Without a real controlling terminal on stdin, including piped input and most CI runners, the command refuses with exit 2 before reading anything. --suggest-project-config without --project-language typescript is still the Go-only batch candidate from v0.4.0.
TypeScript required_layer now reports architecture.layer_bypass, plus reachability facts
In v0.4.0, required_layer had no effect for TypeScript. Now a TypeScript --project-config with required_layer can emit architecture.layer_bypass.
The check uses a pinned, narrow registry:
- Source: a route handler, meaning a named function registered as
x.get|post|put|patch|delete|all("<path>", handler)on a receiver whose type has that method. - Sink: a
PrismaClientmethod from@prisma/client, such asfindMany,create,update,delete, or$queryRaw.
A witness is a resolved call from the handler to the sink that never passes through the required layer. If required_layer matches no files, the search is marked incomplete (project_layer_bypass_coverage_incomplete), and project-change lifecycles fall to unknown.
Every TypeScript project scan also adds possible_call_reachability entries to project_facts in JSON, and a Facts: section in text, for the head revision. Facts are observations, not signals: they never count as findings.
One analyzer run now produces the layer violations, layer bypass, and reachability facts for a revision. That is once for --baseline and twice for --base. If a selected root has candidate files the compiler never incorporated into the import model, project coverage is marked incomplete, with a project_root_scope_incomplete diagnostic naming the files it missed.
Try it
Download the coach binary for your platform from the release assets, or pin the tag:
mise use -g github:lousy-agents/coach@v0.5.0In a TypeScript project, install the supported compiler (npm shown; any of the three origins above works):
npm install --save-dev --save-exact typescript@7.0.2Start with the read-only fit check:
coach codesignal --baseline --check-project --project-language typescript
coach codesignal --baseline --check-project --project-language typescript --format jsonOn a terminal, author a policy, review it, and commit it:
coach codesignal --baseline --suggest-project-config --project-language typescript --output project.json
git add project.json && git commit -m "Add Coach project policy"Run the project scan:
coach codesignal --baseline --project-config project.json --project-la...v0.4.0
Feature release on the v0.x local-pilot line. Headline: opt-in project analysis for coach codesignal. You declare layers and forbidden import pairs; Coach reports architecture.layer_violation. Default file-local analysis is unchanged if you omit --project-config. Coach remains experimental and stays on the 0.x line. This is a local CLI preview, not a 1.0 product, hosted API, or merge gate.
What’s new
Opt-in project analysis (--project-config)
Pass --project-config with a repository-relative JSON document, read at the analyzed revision (not your worktree). You name roots, layers, and forbidden_imports. Coach reports architecture.layer_violation only for import edges that violate that policy. It does not guess your architecture.
Reports that include --project-config use schema_version: "2" and add project-level keys. Without the flag, output stays schema_version: "1".
--project-language go (the default) evaluates layer violations from Go import facts. --project-language typescript evaluates the same layers / forbidden_imports policy from TypeScript import facts. The TypeScript path still expects this repository’s js/semantics layout in the checkout being analyzed. That is not a foreign-repository TypeScript product. required_layer has no CLI effect for TypeScript.
Go required_layer (architecture.layer_bypass)
For Go, an optional required_layer enables architecture.layer_bypass. The check is a pinned, narrow registry: a net/http HandlerFunc source reaching database/sql DB Exec / Query (including the *Context variants) by a statically resolved call path that never passes through the named layer.
Absence is not compliance. Zero findings often means nothing matched the registry, not that no bypass exists.
--suggest-project-config (Go only)
coach codesignal --baseline --suggest-project-config prints a candidate document with roots discovered from committed HEAD. It does not invent layers or forbidden_imports. You add that policy, commit the file, then pass it to --project-config. An uncommitted candidate is not visible to --project-config.
Honest reports
- An incomplete analysis no longer prints an unqualified “no findings” verdict. The text states that the analysis is incomplete.
- JSON always includes
signals,diagnostics, andcoverage(empty-typed when there is nothing to report). With--project-config, the schema-2 project keys are present the same way. --project-configload or validation failures exit 2 and write only to stderr — no report on stdout.
Try it
Download the coach binary for your platform from the release assets. From a Git checkout:
# candidate roots only (Go); review, add layers, commit
coach codesignal --baseline --suggest-project-config
# after the file is committed
coach codesignal --baseline --project-config project.json
coach codesignal --base main --project-config project.jsonFile-local use is unchanged:
coach codesignal --baseline
coach codesignal --base mainSee the coach codesignal section of README.md for the JSON key contract and config examples.
Limits and trust notes
Advisory static analysis only. It does not execute code, prove runtime behavior, write to GitHub, or block merges.
Project analysis reports only edges that violate the policy you wrote. A clean report is not proof the codebase follows an architecture. Check coverage before treating absence as a guarantee.
TypeScript project analysis is not a first-class feature for other repositories. architecture.layer_bypass is not wired for TypeScript in this CLI. Reachability facts are not Signals and are not proof of architecture.
This release also includes coach codesignal --baseline --check-project --project-language typescript: a read-only fit check of committed HEAD. It exits 0 even when there are gaps. Compiler and package-manager checks are not_checked. ready means no gaps among the checks that ran — not that a TypeScript project scan will succeed, and not that Coach has left pilot. It does not install a compiler or package manager.
As in v0.3.0: local CLI preview, no hosted/AWS deployment, no web UI. Coach stays on 0.x / pilot.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle.
Related
| Area | Issue / release |
|---|---|
| TypeScript project-analysis journey (in progress) | #280 |
| Previous release | v0.3.0 |
v0.3.0
Feature release on the v0.x local-pilot line. Headline: a new deterministic CodeSignal security rule helps agentic software engineers catch selected filesystem check-then-act races in AI-generated changes before review.
Coach remains experimental and intentionally stays on the 0.x line. This release adds a backward-compatible signal to the local CLI preview; it is not a 1.0 completeness or hosted-platform promise.
What’s new
security.toctou_check_then_act
Flags a selected non-atomic filesystem pattern: code checks a path or its state, then acts on the same path later under the assumption that the checked state still holds. The gap can let another process or actor create, remove, or replace the file between the check and the act (CWE-367, Time-of-Check Time-of-Use).
| Language | Checks recognized | Act calls recognized |
|---|---|---|
| Go | os.Stat or os.Lstat in the if initializer with a direct err == nil success gate |
os.Open, os.OpenFile, os.Remove, os.RemoveAll, os.ReadFile |
| TypeScript / TSX | Bare existsSync(path) or member-call forms in an if/ while condition |
readFileSync, writeFileSync, appendFileSync, unlinkSync, rmSync |
The signal is:
- medium severity and medium confidence by default;
- located at the filesystem act call, with the check and act preserved as evidence;
- provenance-tagged as a deterministic
semanticsfinding; - rule-versioned as
security.toctou_check_then_actversion1; - available through
coach codesignaldiff and baseline reports, including introduced, existing, and resolved lifecycle classification.
The recommended remediation is EAFP-style: perform the filesystem operation directly and handle its error rather than checking existence in a separate step. A second check such as fs.promises.access does not close the race.
Coverage and reliability
- Go, TypeScript, and TSX analyzer paths are covered with acceptance tests.
- Go/JS parity fixtures cover the new finding and its stable JSON representation.
- Diff and baseline lifecycle tests verify that the security signal survives report classification.
- Dependency and toolchain maintenance updates accompany the feature, including parser, Node.js, AWS SDK, Redis, mise, and release-action refreshes.
Try it
Download the coach binary for your platform from the release assets, then run:
coach codesignal --baseline
# or compare the current worktree with a base ref:
coach codesignal --base mainLook for security.toctou_check_then_act in text or JSON output.
Limits and trust notes
This is an advisory static signal, not a complete security scanner. It does not execute code, provide runtime proof, block merges, or write to GitHub.
Detection is intentionally narrow:
- path identity uses exact source-text equality; aliases and
path.join/path.resolvereconstruction are not followed; - common Go inverse early-return and sentinel-gate forms are excluded;
- TypeScript combined conditions, ternaries, negated/else-only forms, and asynchronous pairs are excluded;
- TypeScript member-call matching is syntactic name matching, not proof that the object is an
fsbinding, so false positives are possible; - cross-file analysis, alias resolution, and scope-aware filesystem reasoning are out of scope.
An empty report means no matched signal was produced for the inputs analyzed. It must not be interpreted as evidence that no TOCTOU risk exists. Coverage and TypeScript binding precision remain pilot follow-up work in #205.
As in the previous release, this is a local preview: no hosted/AWS deployment, pr_history_scan, web UI, or harness hooks are included. The future API/worker path is specified but TOCTOU-specific delivery there is not independently verified.
Binaries
GoReleaser publishes archives for macOS (Apple silicon darwin_arm64 and Intel darwin_x86_64), Linux (linux_x86_64), and Windows (windows_x86_64), plus signed checksums.txt and its cosign signature bundle.
Related
| Area | Issue / PR |
|---|---|
| TOCTOU security signal | #162 |
| TypeScript coverage and binding precision follow-up | #205 |
| TypeScript / TSX detector implementation | #185 |
| Go detector implementation | #179 |
| CodeSignal rule registration | #178 |
| Previous release | v0.2.1 |
v0.2.1 — React component orchestration density
Coach v0.2.1 — React component orchestration density
Patch release on the v0.2 local-pilot line. Headline: a new deterministic CodeSignal rule that names multi-responsibility React client components so pilots can extract panels/hooks before review.
Also includes local-LLM judgment packing improvements, Compose .env config, and a Tree-sitter backend bump.
What's new
structure.react_component_orchestration_density
Flags React client components (TS/TSX) that quietly become orchestration controllers: several independent UI state domains, coordinated multi-setter transitions, mutually exclusive workspace/panel branches, plus at least one of a strong transition shape, imperative DOM UI, or shared panel deps.
| Confidence | high only when the multi-indicator rule fires; otherwise silent |
| Severity | medium (refactor opportunity, not a defect) |
| Surfaces | coach codesignal and baseline-scan reports |
| Boundary | Raw facts in pkg/semantics (react_components); domain classification + emission in pkg/codesignal |
Evidence example:
domains=3;states=3;transitions=1;branches=3;imperative=2;shared=2;client=use_client_directive
Epic: #139 · PR: #150 (tasks #141–#146)
Out of scope (by design): class components, cross-file resolution, HOC unwrap beyond one-level memo/forwardRef, useReducer/external stores, custom-hook inlining, medium-confidence emissions, switch/&& branch forms.
Platform (local pilot)
- Local-LLM judgment packing — packing, caps, and partial agent-finding persist when the model path is constrained (#140)
- Local config —
.env+ bakedsecrets/mount for Compose (#147)
Dependencies
Try it
CLI (no Docker):
coach codesignal --baseline
# or against a base ref:
coach codesignal --base mainLook for structure.react_component_orchestration_density on React client components that coordinate multiple UI domains and workspace panels.
Local platform (unchanged from v0.2.0):
git clone https://github.com/lousy-agents/coach.git && cd coach
git checkout v0.2.1
mise install
mise run platform-up
mise run platform-smoke # expect: platform-smoke: okLimits (same as v0.2.0)
- Local / lab only — do not expose
:8080publicly - No writes to GitHub — no PR comments, checks, or status updates
- Languages: Go, TypeScript, TSX only
- Not in this release: hosted/AWS deploy,
pr_history_scan, web UI, harness hooks
Binaries
coach for darwin_arm64, darwin_x86_64, linux_x86_64, windows_x86_64, plus signed checksums.txt (cosign).
Related
| Area | Issue / PR |
|---|---|
| React orchestration density (epic) | #139 / #150 |
| Local-LLM judgment packing | #140 |
Local .env / secrets mount |
#147 |
| gotreesitter upgrade | #59 / #149 |
| Prior: local pilot platform | v0.2.0 |