Skip to content

Configuration

stylist separates two kinds of configuration:

  • Style rules (allowed colors/fonts, banned terms) live in the ruleset: versioned domain data, owned by the brand team.
  • Operational config (which ruleset, where the API is, failure behavior) is resolved per invocation as described here.

Highest wins:

  1. Command-line flags (-ruleset, …)
  2. STYLIST_* environment variables
  3. The project file .stylist.yaml, found by walking up from the working directory (like .gitignore or .golangci.yml)
  4. Built-in defaults

Checked into the repo root:

ruleset: rules/brand.yaml # path in local mode; ruleset ID in api_url mode
api_url: https://stylist.internal # optional: check via the core API
baseline: .stylist-baseline.yaml # optional: auto-discovered if present
fail_open: true # default true — see below
audience: external # optional: "internal" or "external" — see below
overrides: # optional: skip specific admin-permitted rules — see below
terms:
banned: ["legacy-slogan"]

Relative ruleset/baseline paths resolve against the config file’s directory, so checks behave identically from any subdirectory.

Variable Meaning
STYLIST_RULESET Ruleset path (local) or ID (remote)
STYLIST_API_URL Core API base URL; enables remote mode
STYLIST_API_TOKEN Bearer token for the core API (env-only)
STYLIST_BASELINE Baseline file path
STYLIST_FAIL_OPEN true/false, overrides fail_open
STYLIST_AUDIENCE internal/external, overrides audience
STYLIST_LICENSE License key (server side, unlocks the dashboard)
STYLIST_DASH_TOKEN Dashboard sign-in token (server side)

Secrets (STYLIST_API_TOKEN, STYLIST_LICENSE, STYLIST_DASH_TOKEN) are deliberately not read from .stylist.yaml: checked-in files must never carry credentials. A YAML key like api_token: is ignored.

fail_open: true (the default) means: when checking is impossible — the API is unreachable, the ruleset file is missing, config is broken — hooks warn and allow the operation rather than blocking work. Actual style violations always block regardless.

Set fail_open: false to invert this for strict environments; the hook then exits 2 when checking is impossible.

audience: internal or audience: external declares whether the assets a project/invocation checks are internal-only or client-facing. It’s admin-declared, not inferred. An invalid value (anything besides internal/external) is rejected at load time. Leaving it unset is a legitimate “not yet classified” state, not an error.

Also settable per invocation with -audience (CLI) or STYLIST_AUDIENCE (env), same precedence as every other setting. It’s surfaced on the dashboard’s “By audience” breakdown and in each asset’s check history, and it can also gate which rules apply. See Audience-scoped rules. Leaving it unset applies every rule regardless of audience scoping (the safe default: an audience-scoped rule only ever gets dropped by declaring the other audience, never added by leaving it blank).

A loose asset is one-off, agent-generated content with no .stylist.yaml to declare audience: in (see Loose assets). For a loose asset, audience can also be declared in-content instead of via flag/env; see Context nudges.

overrides: declares which specific rules of a centrally-governed ruleset this project asks to skip. It’s a plain disable list: an override only ever relaxes a rule, it never adds one.

overrides:
colors: true # skip the whole colors block
fonts: false
images: false
terms:
banned: ["legacy-slogan"] # skip by the term's own text
required: []
outdated:
logos: ["old-logo-2019"] # skip by name
colors: ["#ff0000"] # skip by value
fonts: []

It only takes effect for rules the ruleset itself marked overridable: true. See Per-project rule overrides for how a ruleset opts a rule into this, and for how requests against unauthorized rules get reported: never silently swallowed, never an error either. The check just runs as if the request had never been made.

Unlike audience, overrides is file-only: there’s no -overrides flag or STYLIST_OVERRIDES env var, since it only ever makes sense as a per-project, checked-in policy decision, never a per-invocation one. Like audience, it only matters against a centrally-governed ruleset (api_url mode). A local ruleset file is already fully under the project’s own control, so there’s nothing to relax that editing the file directly wouldn’t already do.

With no api_url, checks run in-process against a local ruleset file. With api_url set, ruleset names a server-side ruleset ID, content is POSTed to the core API, and the verdict comes back over HTTP. The CLI, hooks, output, and exit codes are identical in both modes.