# Agent project command discovery

P8 makes the experimental `brass-agent` project-aware enough to stop assuming
`npm test` for every workspace.

The agent still follows the same boundary rule:

```txt
src/core
  ↑
src/agent project command discovery
  ↑
src/agent/cli config loading
```

Command discovery is pure agent logic. It reads observations such as
`package.json` and lockfile existence, then chooses `AgentAction` values. The
runtime core does not know about JavaScript package managers.

## Discovery flow

Before planning, the agent now does this:

```txt
read package.json
check pnpm-lock.yaml
check yarn.lock
check bun.lockb
check bun.lock
check package-lock.json
check npm-shrinkwrap.json
discover validation commands
run discovered validation commands when allowed
run bounded context discovery
ask LLM with command-discovery and context-discovery summaries
```

In `read-only` mode, it still reads/checks files and asks the LLM, but it does
not run shell validation.

## Package manager inference

The package manager is selected in this order:

```txt
config.project.packageManager, when set to npm/pnpm/yarn/bun
package.json packageManager field
lockfiles
npm fallback
```

Lockfiles map as follows:

```txt
pnpm-lock.yaml        -> pnpm
yarn.lock             -> yarn
bun.lockb / bun.lock  -> bun
package-lock.json     -> npm
npm-shrinkwrap.json   -> npm
```

## Validation command discovery

If `config.project.validationCommands` is present, the agent uses those exact
commands and skips script discovery.

Otherwise, it parses `package.json.scripts` and selects up to two validation
commands by default:

```txt
1. first usable test script from test, test:ci, test:unit
2. typecheck/check script when the goal mentions types, or when no test exists
3. lint script when the goal mentions lint, or when no other validation exists
```

The default `test` script generated by `npm init` is skipped:

```json
{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}
```

## Package-manager-specific commands

Script names are converted to command arrays:

```txt
npm  test       -> npm test
npm  typecheck  -> npm run typecheck
pnpm test       -> pnpm test
pnpm typecheck  -> pnpm run typecheck
yarn test       -> yarn test
yarn typecheck  -> yarn run typecheck
bun  test       -> bun run test
bun  typecheck  -> bun run typecheck
```

The shell still executes command arrays with `shell: false`; this avoids
smuggling arbitrary shell syntax through discovered commands.

## Config examples

Force a package manager:

```json
{
  "project": {
    "packageManager": "pnpm"
  }
}
```

Use exact validation commands:

```json
{
  "project": {
    "validationCommands": [
      "pnpm run test:unit",
      "pnpm run typecheck"
    ]
  }
}
```

Prefer custom test script names:

```json
{
  "project": {
    "testScriptNames": ["test:unit", "test:ci", "test"],
    "includeTypecheck": true,
    "maxValidationCommands": 2
  }
}
```

Disable validation commands explicitly:

```json
{
  "project": {
    "validationCommands": []
  }
}
```

That lets the agent read context and ask the LLM without running package scripts.

## Permission interaction

Discovery does not bypass `PermissionService`.

Every discovered command still goes through:

```txt
AgentAction(shell.exec)
  -> PermissionService
  -> ApprovalService when ask
  -> ToolPolicy
  -> Async shell tool
  -> Observation(shell.result)
```

P8 expands the built-in safe shell patterns to cover common validation scripts
for npm, pnpm, yarn, and bun, such as:

```txt
npm run test*
pnpm run typecheck
yarn run lint*
bun run check
```

Projects can still tighten this with:

```json
{
  "permissions": {
    "shell": {
      "inheritDefaults": false,
      "allow": ["pnpm run test:unit"]
    }
  }
}
```

## After apply

When `--apply` / `write` mode successfully applies a patch, the agent reruns the
same discovered validation commands after `patch.applied`.

The completion summary includes the package manager, selected commands, and the
post-apply exit codes.

## P43 health/check script discovery

P43 extends this beyond conventional `test` / `typecheck` / `lint` scripts.
When no usable test script exists, the agent also considers project-health script names such as:

```txt
repo:check
check
*:check
*:doctor
*:health
*:verify
*:validate
*:ci
```

For example, this package no longer looks like it has no validation command:

```json
{
  "scripts": {
    "repo:check": "npm run desktop:build && npm run bridge:doctor"
  }
}
```

The discovered command becomes:

```bash
npm run repo:check
```

If a root `Cargo.toml` is detected and no package script is useful, the agent can fall back to:

```bash
cargo check
```

The project profile summary is included in the planning prompt so the model can reason about mixed workspaces such as npm + Rust + Tauri.
