> For the complete documentation index, see [llms.txt](https://docs.vale.sh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vale.sh/checks/sequence.md).

# sequence

Learn about the sequence extension point.

| Name         | Type         | Description                                                                                                                                                                                                                                             |
| ------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokens`     | `[]NLPToken` | A list of tokens with associated NLP metadata.                                                                                                                                                                                                          |
| `ignorecase` | `bool`       | Makes all matches case-insensitive.                                                                                                                                                                                                                     |
| `exceptions` | `[]string`   | Sentence regions, as regexes; a match beginning inside one is dropped.                                                                                                                                                                                  |
| `model`      | `string`     | A tagger lexicon, `<name>.dict` in `config/dictionaries`: one word per line, then its tags, tab-separated, most common first. Its entries decide a word's tag ahead of the built-in tagger, for rules written against another checker's idea of a noun. |

While most extension points focus on writing *style*, `sequence` aims to support grammar-focused rules.

```yaml
extends: sequence

# `%[4]s` is like `%s`, but specifically refers to the
# 4th token in our sequence.
message: |
  The infinitive '%[4]s' after 'be' requires 'to'.
  Did you mean '%[2]s %[3]s *to* %[4]s'?"
tokens:
  - tag: MD
  - pattern: be
  - tag: JJ
  # The `|` notation means that we'll accept `VB`
  # or `VBN` in position 4.
  - tag: VB|VBN
```

Every `sequence`-based rule is required to have at least one `pattern` (such as `pattern: be`, shown above). This becomes the “anchor” of the sequence: we find all instances of the first pattern and then check that the left- and right-hand sides of the sequence match.

Tokens judge the sentence one word at a time. When a rule needs a judgment about a *region* — for example, “the comma closing a fronted phrase isn’t a list comma” — hand that part to `exceptions`: each entry is a regular expression matched against the sentence, and a sequence match that begins inside one of its matches is dropped. Unlike other checks’ `exceptions`, these are regions rather than vocabulary terms, so the project’s accepted vocabulary is never merged in.

```yaml
# Skip matches that begin inside a fronted phrase.
exceptions:
  - '^(?i:(?:in|on|at|when|while|if)\b[^,]{0,60}),'
```

{% hint style="info" %}
`exceptions`, and the boundary behavior of `negate` described below, require Vale v3.20.0 or later.
{% endhint %}

Each entry in a sequence is known as an `NLPToken` and has the following structure:

```yaml
# [optional]: A regular expression (required
# if `tag` isn't given).
pattern: '...'

# [optional]: If true, indicates that we
# *shouldn't* match this token. A negated token at
# the start or end of a sequence is also satisfied
# by the sentence boundary itself: "not preceded by
# X" holds when nothing precedes the match at all.
negate: true # or false

# [optional]: A part-of-speech tag (required
# if `pattern` isn't given).
tag: '...'

# [optional]: An integer meaning that there may
# be up to `n` (3, in this case) tokens between
# this token and the next one.
skip: 3

# [optional]: How many times the token must occur --
# "at least two nouns", not just one. Each occurrence
# gets its own `skip` window, so `skip: 8, min: 2`
# reads "a noun within eight words, then another noun
# within eight words". The default is 1.
min: 2

# [optional]: A universal part-of-speech tag --
# NOUN, VERB, ADJ, and so on -- instead of a
# Penn Treebank `tag`. Universal tags are
# portable; Penn tags are more precise.
upos: '...'

# [optional]: If true, narrows the alert to this
# token alone. Without it, a match spans every
# token in the sequence -- marking one lets a rule
# require surrounding context while pointing at
# only the part the writer should change.
target: true # or false
```

`sequence`-based are [sentence-scoped](/topics/scopes.md). See [prose/tagging](https://github.com/jdkato/prose?tab=readme-ov-file#tagging) for a full list of supported part-of-speech tags.

{% hint style="info" %}
`min` requires Vale v3.19.0 or later.
{% endhint %}

`min` and `skip` combine to express "at least *n* occurrences within a window." For example, a pronoun is ambiguous when two or more nouns precede it:

```yaml
extends: sequence
message: "Avoid ambiguous pronouns."
level: warning
tokens:
  - tag: NN|NNP|NNPS|NNS
    skip: 8
    min: 2
  - pattern: \w+
    tag: PRP
    target: true
```

This matches "The dog chased the cat until **it** tired" — two nouns, then a pronoun — but not "The dog barked because it hungered." With `target` on the pronoun, the alert covers only `it`:

> The dog chased the cat until it tired. The dog barked because it hungered.

```bash
test.md:1:30:style.Pronouns:Avoid ambiguous pronouns.
```

Without `skip`, `min` means consecutive occurrences: `tag: JJ, min: 2` is two adjectives in a row.

{% hint style="info" %}
Reaching every block, and honoring a declared `scope`, requires Vale v3.17.0 or later. Earlier versions read sentences from paragraphs only.
{% endhint %}

By default, a `sequence` rule reads sentences from **every** block—headings, list items, and table cells as well as paragraphs. Much of a document's prose lives outside its paragraphs, and `sequence` is the only extension point that reads part-of-speech data, so it needs to reach all of it.

To narrow that, declare a `scope`:

```yaml
extends: sequence
message: "matched '%s'"
level: error
# Only take sentences from headings.
scope: heading
tokens:
  - pattern: quick
  - pattern: brown
```

The scope selects which blocks the sentences are drawn from; the rule still matches sentence by sentence within them. A [`doc(...)` selection](/topics/scopes.md#selections) works the same way: the rule reads the sentences inside the selected element.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.vale.sh/checks/sequence.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
