> ## Documentation Index
> Fetch the complete documentation index at: https://docs.finwatch.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing your first Rule

This guide walks you through the process of writing a Watch Script rule from scratch — from thinking about the fraud pattern to testing the finished rule against live transactions. By the end, you'll have a fully functional `.ws` file and a clear understanding of the authoring workflow.

## Thinking About Fraud Patterns

Before you write a single line of code, start by framing the fraud pattern you want to detect as a question:

<Info>
  **"Should I be concerned if a transaction has \[some characteristic]?"**
</Info>

This simple question forces you to articulate the *behavior* you're targeting. Here are some examples:

* "Should I be concerned if a single transaction exceeds \$10,000?"
* "Should I be concerned if the same account sends money to the same destination more than 10 times in 24 hours?"
* "Should I be concerned if a large transaction happens at 3 AM from a normally dormant account?"

The answer to this question becomes your rule. The characteristic becomes your `when` clause. The level of concern becomes your `score`. And the action you'd take becomes your `then` verdict.

For this tutorial, we'll work with a concrete scenario:

<Tip>
  Scenario: Your compliance team has flagged that transactions over \$5,000 to foreign currencies should be reviewed. This is a common AML (Anti-Money Laundering) requirement.
</Tip>

Let's turn this into a rule.

***

## Creating a `.ws` File

Every rule lives in its own `.ws` (Watch Script) file. FinWatch monitors a directory for these files and automatically compiles them when they are created or modified.

### Where to Create the File

Place your `.ws` files in the directory specified by the `WATCH_SCRIPT_DIR` environment variable. The default is `watch_scripts/` relative to where FinWatch is running.

```bash theme={null}
mkdir -p watch_scripts
touch watch_scripts/ForeignCurrencyHighValue.ws
```

### Naming Conventions

* **File name:** Use `PascalCase` matching the rule name (e.g., `ForeignCurrencyHighValue.ws`).
* **One rule per file.** This is a strict convention. Each `.ws` file should contain exactly one rule. This ensures clean Git diffs, clear audit trails, and independent rule management.

### Why One Rule Per File?

When a transaction is blocked or flagged, you need to know *exactly* which rule triggered it. If multiple rules live in one file, debugging and auditing become significantly harder. The one-rule-per-file convention also means each rule has its own version history in Git — you can see when it was created, who changed it, and why.

***

## Step 1: Name Your Rule

Open `ForeignCurrencyHighValue.ws` in your editor and start with the rule declaration:

```go theme={null}
rule ForeignCurrencyHighValue {

}
```

The `rule` keyword declares a new rule. It is followed by the rule's **name** — an identifier that must start with a letter or underscore and can contain letters, digits, and underscores.

**Naming tips:**

* Be descriptive: `ForeignCurrencyHighValue` is far better than `Rule1` or `CurrencyCheck`.
* Use `PascalCase`: It's the convention across the FinWatch ecosystem.
* Describe the *pattern*, not the *action*: `HighFrequencyDestination` is better than `BlockFrequentTransactions` because the verdict might change over time, but the pattern won't.

***

## Step 2: Describe Your Intent

Add a `description` inside the rule block:

```go theme={null}
rule ForeignCurrencyHighValue {
    description "Flags high-value transactions in non-USD currencies for AML review."
}
```

The `description` is a double-quoted string that explains what the rule does and why it exists. This is not just a comment — it's a first-class part of the rule that is stored alongside it and surfaced in logs, API responses, and dashboards.

**Writing a good description:**

Think about who will read this. It won't just be you. It will be:

* A **compliance officer** who needs to understand why a transaction was flagged.
* A **fraud analyst** reviewing a queue of flagged transactions at 2 AM.
* A **regulator** auditing your fraud detection controls.
* A **future developer** who inherits this codebase in two years.

Write for all of them. Be specific about the threshold, the pattern, and the regulatory context.

| Bad                 | Good                                                                               |
| ------------------- | ---------------------------------------------------------------------------------- |
| `"Checks currency"` | `"Flags high-value transactions in non-USD currencies for AML review."`            |
| `"Amount rule"`     | `"Reviews transactions over $5,000 in foreign currencies per BSA/AML compliance."` |

***

## Step 3: Define the Conditions (`when`)

The `when` clause is where you define the logic. Let's build it incrementally.

### A Single Condition

Start with the simplest possible check — just the amount threshold:

```go theme={null}
rule ForeignCurrencyHighValue {
    description "Flags high-value transactions in non-USD currencies for AML review."

    when amount > 5000
}
```

This rule will fire on *any* transaction over \$5,000, regardless of currency. Let's make it more specific.

### Adding a Second Condition with `and`

We only want to flag transactions that are **both** high-value **and** in a non-USD currency:

```go theme={null}
rule ForeignCurrencyHighValue {
    description "Flags high-value transactions in non-USD currencies for AML review."

    when amount > 5000
     and currency != "USD"
}
```

The `and` keyword means **both** conditions must be `true` for the rule to fire. If the amount is \$6,000 but the currency is `"USD"`, the rule does **not** fire.

**Formatting:** Notice the alignment. The `and` keyword is indented to align with the start of the first condition. This is not required by the parser, but it dramatically improves readability. Adopt this convention early.
