Dart workspaces
Hyena switches to workspace analysis when the target root’s pubspec.yaml declares workspace. It analyzes the root package and every discovered member independently, while keeping report paths relative to the common workspace root.
Declare the workspace
Section titled “Declare the workspace”A root can list package directories explicitly and with globs:
name: company_workspaceenvironment: sdk: ^3.10.0
workspace: - apps/mobile - packages/* - tools/codegenEvery non-root member must opt into Dart workspace resolution:
name: company_authresolution: workspaceenvironment: sdk: ^3.10.0Hyena supports explicit entries, nested workspace declarations, and glob entries. The accepted workspace syntax is ultimately determined by the installed Dart SDK, so use syntax that dart pub get accepts for the target project.
A discovered member can declare another workspace to add nested members:
name: company_platformresolution: workspaceenvironment: sdk: ^3.10.0
workspace: - plugins/*Resolve the complete workspace before analysis:
dart pub getdart run hyena_dart analyze .Point the command at the directory that owns the root workspace: declaration. A package directory without that root declaration is analyzed as a single package.
Package boundaries
Section titled “Package boundaries”Hyena builds one analysis result per package, including the root package. Descendant member directories are excluded from every ancestor scan. A source file is therefore analyzed once, under the nearest package boundary and that package’s configuration.
Workspace discovery rejects ambiguous or unsafe membership, including:
- a missing member;
- the same member listed more than once;
- duplicate package names;
- a member outside the target root;
- a resolved member symlink that escapes the target root; and
- a non-root member without
resolution: workspace.
Fix the workspace declaration rather than excluding an invalid member from Hyena. The same package graph should be valid for both Dart and the analyzer.
Cross-package dead-code reachability
Section titled “Cross-package dead-code reachability”A root in an app package can therefore keep the exact declaration it reaches in a shared package, along with that declaration’s reachable dependencies. Package-scoped reports are preserved: a live shared declaration remains in its package’s result rather than moving into the caller’s result.
Matching uses resolved declaration identity, not just a name. If two packages both declare SessionStore, a reference to one does not keep the other alive. References made only from an unreachable caller also do not make their targets reachable, including when caller and target are in different packages.
This joined graph applies to dead-code analysis. Complexity remains calculated and reported independently for each package.
Configuration per package
Section titled “Configuration per package”Without --config, Hyena discovers configuration separately for each package:
- start at the package directory;
- prefer
hyena.yamloveranalysis_options.yamlin the same directory; - walk upward to the nearest configuration; and
- stop at the workspace root.
A member can therefore override the root policy with its own configuration, while packages without a local file inherit the nearest parent configuration inside the workspace.
An explicit configuration is intentionally different:
dart run hyena_dart analyze . --config=tool/hyena-strict.yamlThe selected file applies to every package in the workspace. It may be outside the workspace root because the user, rather than automatic discovery, supplied the path. Review that file before using it; there is no per-member fallback when --config is explicit.
See Configuration for the complete schema.
Package-scoped reports
Section titled “Package-scoped reports”The presentation preserves package boundaries:
| Format | Workspace behavior |
|---|---|
| Console | Prints a separate analysis section for each package with workspace-relative target and finding paths. |
| JSON | Adds workspace.packageCount and a packages array; every targetPath and filePath is workspace-relative. |
| Markdown | Groups summaries and workspace-relative findings by package. |
| HTML | Renders package-scoped sections with workspace-relative paths. |
| SARIF | Keeps source locations relative to the common workspace root. |
Baseline fingerprints also use workspace-relative paths, so matching remains stable across package sections without leaking absolute member locations.
MCP workspace results
Section titled “MCP workspace results”With workspace support in v1.2.0, running dart run hyena_dart:hyena_mcp --root . from the workspace root accepts a relative target such as . and aggregates every workspace package. Returned finding paths remain relative to that configured workspace root.
The MCP server’s existing file, byte, finding, time, and concurrency limits still apply to the complete request. Workspace support does not broaden the configured root or create a second tool. See Safe AI and MCP for the read-only contract and trust boundary.
