Skip to content
Features GitHub

features-cli

One binary for every feature report

A fast CLI written in Rust, distributed on npm and crates.io. Each action is a command, and PATH defaults to the current directory.

  • Run without installing

    npx features-cli@latest serve ./src
  • npm

    npm install -g features-cli
  • cargo

    cargo binstall features-cli

Commands

Eight commands, one per question

  • scan

    List the features. The default action, so features PATH works too.

    features scan [PATH]
  • serve

    Start an HTTP server with the web dashboard, refreshed when files change.

    features serve [PATH]
  • build

    Build a static version of the web dashboard to host anywhere.

    features build [PATH]
  • codeowners

    Generate or update a CODEOWNERS file from feature ownership.

    features codeowners [PATH]
  • find-owner

    Find the owner of a specific file or folder.

    features find-owner <TARGET> [PATH]
  • owners

    Display only the unique list of owners.

    features owners [PATH]
  • check

    Run validation checks on features, such as duplicate names.

    features check [PATH]
  • diff

    List the features touched since a git ref, with their owners.

    features diff [PATH] --since <ref>

Run features <command> --help for the options of a command.

Options

Options at a glance

Grouped by what they change. The second column lists the commands that accept the option.

Output

--json scan, find-owner, owners, diff
Output as JSON
--flat scan
Output features as a flat array instead of a nested structure
--description scan
Include feature descriptions
--coverage scan
Include coverage (always on with --json, serve and build)
--strip-emails all
Remove commit author emails before publishing a build; names are kept

Dashboard

--port <port> serve
Change the port (default: 3000)
--allow-origin <origin> serve
Allow another origin to read the data via CORS. Repeatable; by default only localhost is answered
--build-dir <path> build
Output directory for the static build (default: build)

Diff

--since <ref> diff
Compare with the merge base of <ref> and HEAD, uncommitted changes included
--committed-only diff
Ignore uncommitted and untracked files
--markdown diff
Output a markdown table for pull request comments
--owners-only diff
Print only the unique owners, one per line

CODEOWNERS

--generate-codeowners serve, build, check
Also generate or update the CODEOWNERS file
--codeowners-path <path> codeowners
Custom path and filename (default: CODEOWNERS)
--codeowners-prefix <prefix> codeowners, diff
Prefix for owner names (default: @)

Scanning

--project-dir <path> all
Project directory for CODEOWNERS paths and extra coverage locations
--skip-changes all
Skip computing git history (faster for large repos)
--ignore-path <path> all
Ignore a folder and its subfolders. Repeatable
--include-skipped-dirs all
Also scan folders skipped by default (node_modules)
--coverage-dir <path> all
Custom coverage directory (overrides automatic search)

Legacy flags. Actions used to be flags (--serve, --build, --check, --list-owners, --find-owner). They still work but are deprecated.

Features touched by a change

Comment on pull requests with GitHub Actions

features diff compares the merge base of a ref and HEAD with your working tree. Each changed file is mapped to its closest feature; a renamed file touches both its old and new feature. The command exits with 0 even when nothing is touched.

.github/workflows/features.yml
name: Features touched
on: pull_request

permissions:
  contents: read
  pull-requests: write

jobs:
  features:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0 # the merge base with the target branch is needed

      - name: List touched features
        run: npx features-cli@latest diff src --since origin/${{ github.base_ref }} --committed-only --markdown > features.md

      - name: Comment on the pull request
        env:
          GH_TOKEN: ${{ github.token }}
        run: gh pr comment ${{ github.event.pull_request.number }} --body-file features.md --edit-last --create-if-none

Three output formats

  • --json — features with owner, is_owner_inherited and changed files, plus files outside features.
  • --markdown — a table ready to post as a comment.
  • --owners-only — unique owners, one per line.

Request reviews from owners

Reviewers must be GitHub users or org/team slugs, so set the prefix accordingly.

features diff src --since origin/master --committed-only --owners-only --codeowners-prefix my-org/ \
  | xargs -r -n1 gh pr edit "$PR_NUMBER" --add-reviewer

Pull requests from forks get a read-only token: commenting from those needs a pull_request_target workflow. Read GitHub's security guidance before using it.

Ownership

CODEOWNERS that stay in sync

Ownership declared in feature READMEs is written to a managed section of CODEOWNERS. Anything outside the markers is preserved on each run.

generate CODEOWNERS
# in the current directory
$ features codeowners ./src

# with paths relative to the project root
$ features codeowners ./src --project-dir ./

# combined with serve, build or check
$ features build ./src --generate-codeowners --project-dir ./
CODEOWNERS
# ==== GENERATED BY FEATURES-CLI ====
/src/features/feature-1 @team1
/src/features/feature-2 @team2
# ==== END SECTION GENERATED BY FEATURES-CLI ====

Test coverage

Coverage reports, mapped to features

Run your tests with coverage enabled (for example npx jest --coverage). LCOV and Cobertura reports are found automatically in coverage or .coverage folders.

  1. 1

    PATH/coverage

    the scanned folder

  2. 2

    ./coverage

    where the CLI runs

  3. 3

    project-dir/coverage

    with --project-dir

  4. override

    --coverage-dir

    any custom location

Full reference in the README on GitHub.

See your features in one command

No configuration, no account. Point the CLI at a folder and open the dashboard.

$ npx features-cli@latest serve ./src