Project tool
The project tool reads your config files, runs the right lint, typecheck, test, build and format commands in 23 ecosystems, and checks code before commits.
Copy & share
On this page11 sections
The project tool lets the agent lint, typecheck, test, build and format your code without you telling it which commands your project uses. It reads the config files and lockfiles in the folder and picks the matching commands.
You do not call it yourself. The agent calls it when it needs to check its work. The results show up in the chat like any other tool call.
ActionsLink to this section
| Action | What it runs | Example |
|---|---|---|
lint | The project's linter | project(action: "lint") |
typecheck | The type checker | project(action: "typecheck") |
test | The test suite, or one test file | project(action: "test", file: "src/foo.test.ts") |
build | The build | project(action: "build") |
format | The formatter | project(action: "format") |
check | Typecheck, lint and test at the same time, with one combined report | project(action: "check") |
run | A dev server or a package script | project(action: "run", script: "dev") |
list | The packages in a monorepo | project(action: "list") |
ParametersLink to this section
| Param | Required | What it does |
|---|---|---|
action | yes | One of the actions above |
file | no | Limit the run to one file (useful for test and lint) |
fix | no | Let the linter fix what it can (for example biome --write, eslint --fix, ruff --fix) |
script | no | The script to start with run |
flags | no | Extra command-line flags |
env | no | Environment variables for the command |
cwd | no | The folder to run in, for one package of a monorepo |
timeout | no | Time limit in milliseconds. By default it uses your toolTimeout setting (2 minutes unless you changed it) |
How the toolchain is detectedLink to this section
Empryo looks for well-known files in the working folder:
bun.lock -> bun test, bun run lint, bunx tsc --noEmit
Cargo.toml -> cargo test, cargo clippy, cargo check
go.mod -> go test, golangci-lint run, go build
pyproject.toml -> pytest, ruff check, mypy/pyright
composer.json -> phpunit, phpstan/psalm
Gemfile -> rspec, rubocop
build.gradle -> gradle test, gradle checkIn a JavaScript or TypeScript project, a script in package.json (such as lint, typecheck, test or build) wins over the detected tool.
JS/TS linter detectionLink to this section
When package.json has no lint script, Empryo picks the first linter it finds:
biome.json/biome.jsonc->biome check .oxlintrc.json/.oxlintrc.json->oxlint .eslint.config.js/.eslintrc*->eslint .
Python type checker detectionLink to this section
- If
pyrightconfig.jsonexists, it runspyright. - Otherwise it runs
mypy ..
When the project uses uv, Poetry or Pipenv (it has a uv.lock, poetry.lock or Pipfile.lock), the commands run through that tool, for example uv run pytest.
Full ecosystem supportLink to this section
| Ecosystem | Lint | Typecheck | Test | Build |
|---|---|---|---|---|
| JS/TS (Bun) | biome / oxlint / eslint | tsc | bun test | bun run build |
| JS/TS (npm) | biome / oxlint / eslint | tsc | npm test | npm run build |
| JS/TS (pnpm) | biome / oxlint / eslint | tsc | pnpm test | pnpm build |
| JS/TS (Yarn) | biome / oxlint / eslint | tsc | yarn test | yarn build |
| Deno | deno lint | deno check | deno test | -- |
| Rust | cargo clippy | cargo check | cargo test | cargo build |
| Go | golangci-lint / go vet | go build | go test | go build |
| Python | ruff / flake8 | pyright / mypy | pytest | -- |
| PHP | pint / php-cs-fixer | phpstan / psalm | phpunit | -- |
| Ruby | rubocop | -- | rspec / rails test | -- |
| Swift | swiftlint | swift build | swift test | swift build |
| Elixir | credo | dialyzer | mix test | mix compile |
| Java/Kotlin (Gradle) | gradle check (or spotless / ktlint) | gradle compileJava / compileKotlin | gradle test | gradle build |
| C/C++ (CMake) | clang-tidy | cmake build | ctest | cmake build |
| Dart/Flutter | dart analyze | dart analyze | flutter test | flutter build |
| Zig | zig fmt --check | zig build | zig build test | zig build |
| Haskell | hlint | stack build | stack test | stack build |
| Scala | scalafmt --check | sbt compile | sbt test | sbt compile |
| .NET/C# | dotnet format | dotnet build | dotnet test | dotnet build |
| iOS/Xcode | swiftlint | xcodebuild build | xcodebuild test | xcodebuild build |
| Java (Maven) | checkstyle | mvn compile | mvn test | mvn package |
| C/C++ (Make) | -- | -- | make test | make |
| Clojure | clj-kondo | -- | lein test / clj -M:test | lein uberjar |
A -- means Empryo found no standard command for that step, so the action reports that nothing is configured.
Pre-commit checksLink to this section
When the agent commits with git commit -m "…" through the shell tool, Empryo first runs your linter and type checker. If they fail, the commit does not happen and the agent gets the errors so it can fix them.
What runs depends on the project:
- JS/TS: your linter and
tsc --noEmit, for examplebiome check . && tsc --noEmit - Deno:
deno lint && deno check . - Rust:
cargo clippy && cargo check - Go:
golangci-lint run && go build ./...(orgo vetwhen there is no golangci-lint config) - Python:
ruff check(orflake8) followed bypyrightormypy
This check does not depend on the agent remembering to lint. Empryo runs it on every agent commit.
The checks have a 15-second limit. Commits you make yourself, outside Empryo, are not affected.
Monorepo discoveryLink to this section
project(action: "list") finds the packages in a workspace.
Supported workspace formatsLink to this section
- pnpm:
pnpm-workspace.yaml - npm/yarn: the
workspacesfield inpackage.json - Cargo:
[workspace] membersinCargo.toml - Go:
usedirectives ingo.work
Example outputLink to this section
5 packages:
@myapp/web -- packages/web (biome) [lint, typecheck, test]
@myapp/api -- packages/api (biome) [lint, typecheck, test]
@myapp/shared -- packages/shared (biome) [lint, typecheck]
@myapp/cli -- packages/cli (biome) [lint]
@myapp/docs -- packages/docs [test]
Use project(action: "lint", cwd: "<path>") to target a specific package.Each package is detected on its own, so the list shows what each one actually supports. When the agent tests a single file, Empryo runs the test from the package that owns that file instead of the whole workspace.
When the agent uses the shell insteadLink to this section
If the agent runs a command like bun run lint or cargo clippy through the shell, the command still runs. The result adds a short reminder to use the project tool next time, because its output is structured and shows up properly in the UI.
Command succeeded. Next time use project(action: "lint") -- it auto-detects
the toolchain, results are structured, and output is visible in the UI.