coach

module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: BSD-2-Clause

README

coach

coach is an experimental AI coach for people (and agents) who write software. The thing you can use today is a local CLI: it reads a Git checkout, analyzes Go / TypeScript / TSX source, and prints advisory structural signals.

Coach stays on the 0.x line on purpose. It does not contact GitHub or call a model on this path. File-local analysis is Tree-sitter over committed Git objects. TypeScript --project-config additionally runs a host Node process and the TypeScript compiler; that is still local, not the platform preview.

Contract

  • Languages: Go, TypeScript, TSX. Other files get an unsupported_language diagnostic and are skipped.
  • Input: committed Git objects at the selected revision, not the dirty worktree. Uncommitted edits are invisible.
  • Git: git must be on PATH. No Docker, no API key, no network for the default CLI path.
  • Advisory: a completed analysis exits 0 even when it found signals. Coach does not gate merges.
  • Absence is not a clean bill of health. An empty signal set means no matched rule for the inputs that were analyzed.

Full flags, JSON schema, exit codes, rule IDs, and library quickstarts: CLI contract.

Run

From any Git worktree. Prefer a one-shot that does not mutate a global toolchain:

mise exec github:lousy-agents/coach -- coach codesignal --base main
coach codesignal --base main          # diff HEAD against main
coach codesignal --baseline           # every tracked Go/TS/TSX file at HEAD
coach codesignal --base main --format json

--base can be any ref Git can resolve (branch, tag, or SHA). Default output is text. --base and --baseline are mutually exclusive.

Default --scope is production. --build-target <pattern> further limits Go production reachability; it is a no-op under --scope all.

Exit codes
Code Meaning
0 Analysis completed (signals or none). Not a quality gate.
1 Operational failure (not a git repo, missing git, unresolvable --base, empty repo, I/O).
2 Usage or invalid --project-config, or a TypeScript scan that cannot resolve a supported compiler or host Node (empty stdout, one stderr line).
What you should see

A short text report per signal (path, line, lifecycle, changed, evidence, why it matters, recommendation), or a quiet report if nothing matched. lifecycle is introduced / existing / resolved / unknown.

Diff-mode limits (do not treat these as a clean PR):

  • Added files are analyzed but classified unknown; they do not increment introduced_signals.
  • Renames and copies are skipped with an unsupported_change_type diagnostic.

Text line is 1-based. JSON location.start_row is 0-based.

Install

Install mise if you do not already have it, then pin the CLI from GitHub Releases:

curl https://mise.run | sh
~/.local/bin/mise use -g github:lousy-agents/coach

That mutates a global mise config. Hook mise into your shell so coach is on PATH (pick the one you use):

echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc && eval "$(~/.local/bin/mise activate bash)"
# echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc && eval "$(~/.local/bin/mise activate zsh)"
# ~/.local/bin/mise activate fish | source

Pin a release if you want a fixed binary (latest published tag is v0.6.0):

mise use -g github:lousy-agents/coach@v0.6.0

Release archives exist for darwin_arm64, darwin_x86_64, linux_x86_64, and windows_x86_64. There is no linux_arm64 build yet.

From source instead of the release binary

This path uses the repo's mise.toml to pin the dev toolchain (Go 1.27.1, Node 24). That is not the same as installing the published coach binary.

git clone https://github.com/lousy-agents/coach.git
cd coach
mise install
mise exec -- go install ./cmd/coach
Signed archive without mise

Download the archive for your platform from Releases, verify checksums.txt with cosign, then put coach on your PATH. Commands: CLI contract.

Preview — experimental, try it now

These commands work on the current CLI. They may change without a 1.0 promise. Absence of findings is not compliance.

1. Project-level architecture policy

Opt into cross-file layer checks with a committed JSON config. Coach does not guess your architecture — you declare layers and forbidden import edges.

# Go: discover module/workspace roots (candidate only — review, add layers, commit)
coach codesignal --baseline --suggest-project-config

# after the file is committed at the analyzed revision
coach codesignal --base main --project-config project.json
coach codesignal --baseline --project-config project.json --project-language typescript

--project-config is read from the analyzed revision, not your dirty worktree. An uncommitted candidate is invisible to the scan. A valid config switches the report to schema_version: "2" and can emit architecture.layer_violation. required_layer can also emit architecture.layer_bypass (Go and TypeScript) on a narrow handler→SQL registry.

TypeScript --project-config uses Coach's embedded analyzer and a host-resolved compiler whose own package.json version is in the supported set (7.0.2 today). Version ranges (^, ~, latest) never count. If you previously vendored Coach's analyzer under the analyzed repository, you can delete that copy. --suggest-project-config never invents layers or forbidden_imports, and it never auto-applies a config.

Go --suggest-project-config prints a candidate. TypeScript --suggest-project-config --project-language typescript is an interactive TTY session and writes nothing until you confirm. Do not run it unattended.

2. TypeScript project readiness
coach codesignal --baseline --check-project --project-language typescript
coach codesignal --baseline --suggest-project-config --project-language typescript

Run --check-project first. It is read-only: it reports compiler, Node, and policy fit and exits 0 so you inspect the result instead of treating process status as a gate. It is not a scan. A scan that cannot resolve a supported compiler or host Node exits 2 with empty stdout and one stderr line.

Coach's supported Node majors are exactly 24 and 26. Any other major is the node_unsupported readiness gap. @lousy-agents/coach-semantics declares this as engines.node: "^24 || ^26".

--prepare-compiler is a consented, interactive mise TypeScript compiler-setup session (requires a TTY; refuses otherwise). It prompts before installing.

Still being built — do not expect these to work yet: unattended package-manager setup for the scanned project, Bun as a project runtime, and a packaged foreign-repository TypeScript journey.

Separate lab: local platform

The CLI above is the default product. A Docker API + worker stack can add agent judgments on a baseline scan. That path uses Docker, may call a model, and may read GitHub. It is not the default install.

Verified in CI: Path A (mise run platform-up / platform-smoke) with the stub model. Paths B (real local model) and C (live GitHub.com) are operator labs. Findings are tagged source=deterministic or source=agent; agent output cannot suppress a deterministic finding.

Local Coach quickstart.

Libraries

Analyzer as a library rather than the CLI — not required to run coach:

Directories

Path Synopsis
cmd
acceptance-guard-preflight command
Command acceptance-guard-preflight is the activation entry point for internal/acceptanceharness's ambient-credential guard: run it before any acceptance suite starts (see mise.toml's test-acceptance-fast task).
Command acceptance-guard-preflight is the activation entry point for internal/acceptanceharness's ambient-credential guard: run it before any acceptance suite starts (see mise.toml's test-acceptance-fast task).
acceptance-style-guard command
Command acceptance-style-guard fails if any acceptance_test.go or *_acceptance_test.go under the module root does not import github.com/onsi/ginkgo/v2 and reference a Ginkgo suite/spec API, except an explicit allowlist (see internal/acceptancestyle).
Command acceptance-style-guard fails if any acceptance_test.go or *_acceptance_test.go under the module root does not import github.com/onsi/ginkgo/v2 and reference a Ginkgo suite/spec API, except an explicit allowlist (see internal/acceptancestyle).
coach command
Command coach is the composition-root CLI for the coach project.
Command coach is the composition-root CLI for the coach project.
coach-api command
Command coach-api is the composition-root HTTP service for the coach platform: it wires internal/authn (Coach JWT auth, optional GitHub OAuth login, config-gated test mint) and internal/coachapi (POST /v1/jobs, GET /v1/jobs/{id}, GET /v1/jobs/{id}/report) behind a live authz.RepoAuthorizer and a Redis Streams queue.TaskQueue into one runnable server.
Command coach-api is the composition-root HTTP service for the coach platform: it wires internal/authn (Coach JWT auth, optional GitHub OAuth login, config-gated test mint) and internal/coachapi (POST /v1/jobs, GET /v1/jobs/{id}, GET /v1/jobs/{id}/report) behind a live authz.RepoAuthorizer and a Redis Streams queue.TaskQueue into one runnable server.
coach-worker command
Command coach-worker claims work through queue.TaskQueue, persists claim/heartbeat/fenced writes via coachapi.WorkerJobStore, and runs the repo_baseline_scan handler.
Command coach-worker claims work through queue.TaskQueue, persists claim/heartbeat/fenced writes via coachapi.WorkerJobStore, and runs the repo_baseline_scan handler.
codesignal-report command
Command codesignal-report reads a batch of NDJSON lines from stdin, accumulates a single codesignal.Input, and writes exactly one JSON codesignal.Report to stdout.
Command codesignal-report reads a batch of NDJSON lines from stdin, accumulates a single codesignal.Input, and writes exactly one JSON codesignal.Report to stdout.
fakegithub-server command
Command fakegithub-server runs internal/fakegithub as a standalone HTTP process, packaging the issue #79 Task 0.3 thin-offline-proof fixture (internal/acceptanceharness/thinproof) as an internal-network Compose service rather than an in-process httptest.Server.
Command fakegithub-server runs internal/fakegithub as a standalone HTTP process, packaging the issue #79 Task 0.3 thin-offline-proof fixture (internal/acceptanceharness/thinproof) as an internal-network Compose service rather than an in-process httptest.Server.
model-stub command
Command model-stub serves the compose OpenAI-compatible HTTP stub from internal/modelgateway so core smoke can exercise worker → Envoy AI Gateway → backend without model weights.
Command model-stub serves the compose OpenAI-compatible HTTP stub from internal/modelgateway so core smoke can exercise worker → Envoy AI Gateway → backend without model weights.
platform-smoke command
Command platform-smoke is the end-to-end credential-free smoke for the local platform compose stack (Baseline Scan Story 4 / Task 10): mint → submit repo_baseline_scan → poll → assert provenance-tagged report.
Command platform-smoke is the end-to-end credential-free smoke for the local platform compose stack (Baseline Scan Story 4 / Task 10): mint → submit repo_baseline_scan → poll → assert provenance-tagged report.
semantics-json command
Command semantics-json exposes internal/jsbridge as a long-running newline-delimited-JSON server on stdin/stdout, so non-Go hosts (the js/semantics package) can call pkg/semantics without linking CGO themselves.
Command semantics-json exposes internal/jsbridge as a long-running newline-delimited-JSON server on stdin/stdout, so non-Go hosts (the js/semantics package) can call pkg/semantics without linking CGO themselves.
semantics-wasm-smoke command
Stub entry point so `go build ./...` / `go vet ./...` on native platforms don't fail with "build constraints exclude all Go files".
Stub entry point so `go build ./...` / `go vet ./...` on native platforms don't fail with "build constraints exclude all Go files".
thinproof-preflight command
Command thinproof-preflight is the no-pull/offline Compose preflight for issue #79's Task 0.3 thin offline proof (see docs/architecture/acceptance-harness.md section 2's binding contract): it checks, via `docker image inspect`, that the two local images deploy/compose/thinproof's docker-compose.yml expects already exist, before any `docker compose up` runs.
Command thinproof-preflight is the no-pull/offline Compose preflight for issue #79's Task 0.3 thin offline proof (see docs/architecture/acceptance-harness.md section 2's binding contract): it checks, via `docker image inspect`, that the two local images deploy/compose/thinproof's docker-compose.yml expects already exist, before any `docker compose up` runs.
thinproof-runner command
Command thinproof-runner is the external test-runner container for issue #79's Task 0.3 thin offline proof: it exercises the fake-GitHub -> pkg/githubingest -> pkg/semantics -> pkg/codesignal path against a fake GitHub service reachable only at FAKE_GITHUB_BASE_URL (e.g.
Command thinproof-runner is the external test-runner container for issue #79's Task 0.3 thin offline proof: it exercises the fake-GitHub -> pkg/githubingest -> pkg/semantics -> pkg/codesignal path against a fake GitHub service reachable only at FAKE_GITHUB_BASE_URL (e.g.
deploy
internal
acceptanceharness
Package acceptanceharness provides the offline acceptance-test guard rails for Feature Zero (GitHub issue #76, epic #73): an ambient-credential scanner that flags leaked-in, CI-style GitHub/AWS credentials before an acceptance suite runs, and a no-egress http.RoundTripper that makes an accidental public network call (e.g.
Package acceptanceharness provides the offline acceptance-test guard rails for Feature Zero (GitHub issue #76, epic #73): an ambient-credential scanner that flags leaked-in, CI-style GitHub/AWS credentials before an acceptance suite runs, and a no-egress http.RoundTripper that makes an accidental public network call (e.g.
acceptanceharness/agentloopharness
Package agentloopharness defines test/harness seams that a later epic's internal/agentloop package will import from its own tests: a scripted model-gateway stand-in (ScriptedGateway) and a recording tool-call broker (RecordingToolRegistry).
Package agentloopharness defines test/harness seams that a later epic's internal/agentloop package will import from its own tests: a scripted model-gateway stand-in (ScriptedGateway) and a recording tool-call broker (RecordingToolRegistry).
acceptanceharness/queueconformance
Package queueconformance defines a black-box behavioral contract for the eventual TaskQueue port described by ADR-006, and a reusable conformance suite (Run) that exercises any Queue implementation against it.
Package queueconformance defines a black-box behavioral contract for the eventual TaskQueue port described by ADR-006, and a reusable conformance suite (Run) that exercises any Queue implementation against it.
acceptanceharness/thinproof
Package thinproof is the shared, data-as-code fixture for GitHub issue #79's Task 0.3 thin offline proof: a single small file, at a fixed owner/repo/ref/path, served by internal/fakegithub and read back through pkg/githubingest's public GitHubFileReader API.
Package thinproof is the shared, data-as-code fixture for GitHub issue #79's Task 0.3 thin offline proof: a single small file, at a fixed owner/repo/ref/path, served by internal/fakegithub and read back through pkg/githubingest's public GitHubFileReader API.
acceptancestyle
Package acceptancestyle mechanically checks that every acceptance_test.go and *_acceptance_test.go imports github.com/onsi/ginkgo/v2 and references a Ginkgo suite/spec API (RunSpecs, Describe, It, …), except an explicit allowlist.
Package acceptancestyle mechanically checks that every acceptance_test.go and *_acceptance_test.go imports github.com/onsi/ginkgo/v2 and references a Ginkgo suite/spec API (RunSpecs, Describe, It, …), except an explicit allowlist.
agentloop
Package agentloop is a bounded tool-call broker over a typed registry (ADR-005).
Package agentloop is a bounded tool-call broker over a typed registry (ADR-005).
authn
Package authn implements Coach-signed JWT issue, validation, jti denylist revocation, HTTP auth middleware, optional GitHub OAuth App login (no scope), and a config-gated test-mint path for protected /v1 routes (ADR-001).
Package authn implements Coach-signed JWT issue, validation, jti denylist revocation, HTTP auth middleware, optional GitHub OAuth App login (no scope), and a config-gated test-mint path for protected /v1 routes (ADR-001).
authz
Package authz implements ADR-003's synchronous, submit-time repository authorization check: a principal may submit a scan of owner/repo only if the Coach GitHub App installation can read the repository and the principal has a GitHub-recognized role in it.
Package authz implements ADR-003's synchronous, submit-time repository authorization check: a principal may submit a scan of owner/repo only if the Coach GitHub App installation can read the repository and the principal has a GitHub-recognized role in it.
coachapi/queue
Package queue defines the application-owned TaskQueue and EventBus ports required by ADR-006 (docs/architecture/ADR-006-watermill-queue-abstraction.md): coach-api and coach-worker depend only on these interfaces, never on Watermill or a specific broker's types, so the backend (Redis Streams, SQS, ...) can be swapped without touching domain code.
Package queue defines the application-owned TaskQueue and EventBus ports required by ADR-006 (docs/architecture/ADR-006-watermill-queue-abstraction.md): coach-api and coach-worker depend only on these interfaces, never on Watermill or a specific broker's types, so the backend (Redis Streams, SQS, ...) can be swapped without touching domain code.
coachapi/queue/redisstream
Package redisstream implements the internal/coachapi/queue.TaskQueue port (ADR-006, docs/architecture/ADR-006-watermill-queue-abstraction.md) on top of Watermill's Redis Streams pub/sub (github.com/ThreeDotsLabs/watermill-redisstream), for coach's non-AWS / self-hosted deployment target.
Package redisstream implements the internal/coachapi/queue.TaskQueue port (ADR-006, docs/architecture/ADR-006-watermill-queue-abstraction.md) on top of Watermill's Redis Streams pub/sub (github.com/ThreeDotsLabs/watermill-redisstream), for coach's non-AWS / self-hosted deployment target.
coachapi/queue/sqs
Package sqs implements the internal/coachapi/queue.TaskQueue port (ADR-006, "Provider configuration" -> aws-sqs) on top of Amazon SQS.
Package sqs implements the internal/coachapi/queue.TaskQueue port (ADR-006, "Provider configuration" -> aws-sqs) on top of Amazon SQS.
codesignalcli
Package codesignalcli implements the Git-facing plumbing behind the `coach codesignal` subcommand: resolving revisions and selecting the files a CodeSignal report should analyze.
Package codesignalcli implements the Git-facing plumbing behind the `coach codesignal` subcommand: resolving revisions and selecting the files a CodeSignal report should analyze.
fakegithub
Package fakegithub is a Coach-owned, fixture-driven fake GitHub HTTP service for offline acceptance testing.
Package fakegithub is a Coach-owned, fixture-driven fake GitHub HTTP service for offline acceptance testing.
jsbridge
Package jsbridge defines the JSON protocol that exposes pkg/semantics to JavaScript/TypeScript consumers, plus the single handler both transport backends (WASM and stdio CLI) call.
Package jsbridge defines the JSON protocol that exposes pkg/semantics to JavaScript/TypeScript consumers, plus the single handler both transport backends (WASM and stdio CLI) call.
modelgateway
Package modelgateway is the sole inference seam for structured judgment: request in → schema-validated response out.
Package modelgateway is the sole inference seam for structured judgment: request in → schema-validated response out.
projectbridge
Package projectbridge defines the JSON protocol between pkg/projectmodel's TypeScript sidecar client and a pinned local Node/TypeScript sidecar subprocess that produces raw TypeScript/TSX import facts from an immutable snapshot (issue #214).
Package projectbridge defines the JSON protocol between pkg/projectmodel's TypeScript sidecar client and a pinned local Node/TypeScript sidecar subprocess that produces raw TypeScript/TSX import facts from an immutable snapshot (issue #214).
rubrics
Package rubrics holds versioned LLM-as-judge definitions, prompt assembly, and agent-loop tool adapters for seed rubrics (ADR-005).
Package rubrics holds versioned LLM-as-judge definitions, prompt assembly, and agent-loop tool adapters for seed rubrics (ADR-005).
tstestutil
Package tstestutil holds helpers shared by Ginkgo acceptance tests that copy this repository's installed TypeScript compiler into a fixture worktree.
Package tstestutil holds helpers shared by Ginkgo acceptance tests that copy this repository's installed TypeScript compiler into a fixture worktree.
pkg
codesignal
Package codesignal turns pkg/semantics analysis results into prioritized, change-aware coaching signals.
Package codesignal turns pkg/semantics analysis results into prioritized, change-aware coaching signals.
githubingest
Package githubingest reads individual file contents from a GitHub repository via the GitHub Contents API, authenticated as a GitHub App installation.
Package githubingest reads individual file contents from a GitHub repository via the GitHub Contents API, authenticated as a GitHub App installation.
projectmodel
Package projectmodel defines deterministic, offline, whole-repository structural facts about a codebase.
Package projectmodel defines deterministic, offline, whole-repository structural facts about a codebase.
semantics
Package semantics extracts deterministic structural facts from raw source bytes (syntax validity, imports, branching metrics, constructor-like patterns, mutates_input) using Tree-sitter grammars.
Package semantics extracts deterministic structural facts from raw source bytes (syntax validity, imports, branching metrics, constructor-like patterns, mutates_input) using Tree-sitter grammars.
semantics/internal/engine
Package engine defines the narrow tree-sitter surface pkg/semantics relies on.
Package engine defines the narrow tree-sitter surface pkg/semantics relies on.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL