tula

Security model

Non-custodial, and read-only for the moment — placing trades will come later.

That rules out losing your funds. It does not rule out losing your data: one file on your machine holds a key to every venue you connect.

Every copy comes from here. tula is built by github.com/hsnice16/tula and published to its install page, Homebrew and npm — one binary, built once. The attestation covers the release archive, so that is what gh attestation verify reads; npm repacks the same binary and cannot be checked that way. An archive it turns down did not come from this project.

Promises, and what enforces them

No code path can move funds off a venue
no withdrawal or transfer endpoint, in any connector
Nothing places an order, for the moment
the build fails if an order endpoint appears
A key that can move funds is turned away, not warned about
checked against the venue at connect time
Your keys never reach the model
the agent layer cannot import a connector or the store
Your keys stay on your machine, in one file
mode 600, and refused if anything else can reach it
A price-source key is typed into a prompt
never on a command line your history would keep

Where the edges are

Never a seed phrase

Reading on-chain takes a public address, nothing more. No box on any screen asks for a seed phrase, and anything that does is not tula. The one private key it ever loads is a Coinbase CDP key, which signs read requests and cannot move funds — the build fails if key handling shows up in any other file.

Not encrypted at rest

Your keys are plain JSON in one file, mode 600. Locking it would mean keeping the key to the lock right beside it, which protects nothing, or asking you for a passphrase, which breaks any command that runs on its own. So: safe from other people on the machine, not from a backup or from anything already running as you.

Unknown is a value

Kraken cannot tell what a key is allowed to do without placing an order, so tula says unknown rather than safe. A missing price means no value shown, never a zero. A key that can trade is turned away today as well; the one that will never be let through is withdraw.

The model never computes

Every number on screen is worked out in plain code and rounded before the model sees it. The model asks one interface for answers, and cannot reach a venue or your keys.

The install path is checked

The installer stops if the published checksum does not match. Where the GitHub CLI is present and signed in it also checks a sigstore attestation and stops if that fails; where it is not, it says plainly that provenance was not proven. TULA_REQUIRE_ATTESTATION=1 makes that a refusal too.

Text tula did not write

Two kinds of text reach the screen and the model from outside: an asset symbol — as a venue’s listing spells it, or as an Aave reserve contract returns it — and a venue’s own error text when one fails. Both are cut to a length limit and squashed onto one line on the way in, so neither can pose as an instruction. No memo, NFT metadata or protocol description is read at all.

Network egress

The venues you connect, a public Ethereum RPC, the price source, the token list. Anthropic only when you ask a question, and only the numbers already worked out — never a key. The binary sends nothing about how you use it. This site is measured with Google Analytics; the binary is not.

Found a hole? Report it privately, never as a public issue. SECURITY.md says how to send it, what counts as in scope, and how long a reply takes.