Skip to main content
Glama
README.md
# veto

A checklist for a long call. It answers `pass`, `fail`, or `watchlist`, and
it does not recommend a trade.

The rules came out of a week of checking the same names twice and finding
that the second check disagreed with the first. The useful part was not the
names. It was the refusals: an entry mode that was "near" its number, an
analyst target copied from a stale snippet, a spread whose short leg broke a
rule the long leg had already satisfied. Those are tests now. The names are
examples of a reading, not ideas.

Nothing to install beyond Python 3.9.

## Try it

```sh
pip install veto-check
veto check examples/se.txt
python3 -m veto check examples/se.txt
python3 -m veto check examples/clear.txt
python3 -m veto check examples/spread.txt
```

A reading is one `name: value` per line. A missing value fails the rule that
needs it. There is no "close enough": RSI of 30.01 does not pass a rule
written as 30.

`examples/se.txt` fails both entry modes, so the result is `watchlist`. Not a
smaller trade. `examples/bmy.txt` fails the analyst check first, at 8.3%
against a rule that wants 20%. `examples/spread.txt` passes an entry mode and
then fails because the short leg is too short, too far from the money, and
expires after earnings.

## The rules

Applied in this order. The first one is first because it removes a name
before the rest of the numbers are worth collecting.

| Rule | Passes when |
|---|---|
| analyst upside | target is at least 20% above the price |
| mode A | RSI is 30 or below, and the MACD histogram is positive |
| mode B | RSI is from 45 to 65, and a catalyst falls inside 30 days |
| iv rank | below 30 |
| FOMC | the decision is more than 48 hours away, or already past |
| gap | the open is not more than 5% |
| earnings | a hold-or-exit decision is already written down |
| diagonal | only when the reading is a spread: each leg 60 to 120 days, at the money or one strike out, and the short leg expires before earnings |

One of the two modes has to pass. The other rules all have to pass. Both
modes failing is `watchlist`. A mode passing while another rule fails is
`fail`.

## As an MCP server

```sh
python3 -m veto serve
```

This speaks [MCP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports)
over stdin and stdout: one JSON-RPC message per line, logs on stderr, nothing
else on stdout. It implements `initialize`, `tools/list`, `tools/call`, and
`ping`. The one tool is `check`, and its arguments are the same fields as the
text file.

A host that already runs other servers adds this beside them. The decision
does not change because it arrived over the protocol: `serve` calls the same
function `check` does. A client that would rather not speak MCP can shell out
to `python3 -m veto check` and read the text.

```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"example","version":"0"}}}
```

## What it will not do

It does not fetch a price, an analyst target, or an option chain. Those
numbers go stale, and a tool that fetches them starts pretending the fetch
cannot be wrong. You bring the figures. It also does not size a position,
pick a strike, or tell you to buy anything. The output is whether the reading
cleared rules you can read in `veto/rules.py`.

## Tests

```sh
python3 -m unittest discover -s tests
```

TDQS

A3.5/5.0

Scored across 1 tool

Disambiguation5/5

There is only one tool, so there is no possibility of selecting among overlapping or confusing alternatives. Its purpose—returning pass, fail, or watchlist for a long-call reading against fixed rules—is clearly stated.

Naming Consistency4/5

With a single tool, there is no cross-tool naming inconsistency. The name 'check' is concise and verb-based, though generic and not especially descriptive of the veto/rule-checking domain.

Tool Count3/5

The server appears narrowly scoped to one validation decision, so one tool can be sufficient. However, a single-tool surface is thin for a standalone server and leaves little room for related operations such as rule inspection or explanation.

Completeness4/5

The core decision operation is covered, including pass/fail/watchlist outcomes and a clear statement that missing numbers fail applicable rules. Minor gaps remain around diagnostics, such as explaining which rule failed or exposing the fixed rule set.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues