A second brain that marks its own homework.
Notes are plain markdown in a folder — the same folder Obsidian opens. Some of those notes make a claim about the future. Those settle themselves.
python 3.10+ · zero dependencies · MIT
the program does not touch it — what that means
git clone https://github.com/DefiLeoo/YOINK && cd YOINK
pip install -e .
yoink demo # writes a vault that already has a life
yoink # open it /\_/\
( o.o)
> ^ <
a vault with a life · ~/yoink-vault
35 notes · 14 alive · 21 never opened again
5 claims settled on the spot · 2 still open
said 75%, right 40% — +35 pts
every number above was computed from those files, not written here.
Two things that usually live apart, in one folder.
An Obsidian vault. Markdown files with frontmatter and [[wikilinks]].
Open the same folder in Obsidian and everything works — the links resolve, the
tags show up, the graph draws. Nothing is in a database. Nothing is in a format
you need this tool to read.
A terminal. Four panes, keyboard only, launched with one word. Capture, search, follow links, read, settle — without leaving the shell you were already in.
And one thing that lives in neither.
Every note app can tell you how many notes you have.
None of them can tell you whether a single one of them was right.
yoink adds four lines to a note's frontmatter, and those four lines turn a thought into a bet with a date on it:
---
title: Robinhood Chain testnet clears 10M transactions
claim: tx count is at or above 10000000
settles: 2026-10-01
reads: chain:robinhood-testnet/txcount
test: gte 10000000
confidence: 0.7
---When the date arrives, yoink settle reads the source, applies the test, and
writes the answer back into the note itself:
outcome: false
reading: 8412998
settled: 2026-10-01T09:14:22
read_from: robinhood-testnet @ block 9412998Your vault now holds not only what you thought, but what happened — attached to the thought, in the same file, in plain text, forever.
That is the whole trick. Everything else in this repository exists to make it work and to stop you from cheating at it.
Because the notes carry outcomes, the vault can be scored. yoink score prints
two things nobody's note app wants to print.
the vault
──────────────────────────────────────────────────────────────
notes 35
words 851
links 16
alive 14 (40%)
dead 21 nothing links to them and you never went back · yoink dead
the record
──────────────────────────────────────────────────────────────
settled 5 graded 5
said 75% average confidence, folded to the side you took
right 40% how often that side was the right one
gap +35 pts overconfident
brier 0.388 0 perfect · 0.25 a coin · 1 certain and wrong
Dead notes. A note is alive if something links to it, it links to something, you came back to it after the day you saved it, or it carries a bet that has not closed. Otherwise it is dead. In most vaults this is a third of everything, and it is invisible, which is why people believe their vault is working.
The gap. said − right. You said 75%; you were right 40% of the time. That
is 35 points of overconfidence, computed from your own notes. It cannot be
improved by writing more notes — only by being right, or by saying a smaller
number and meaning it.
The grading is the Brier score, (p − outcome)², used for weather forecasts
since 1950 and chosen for one property: your best expected score comes from
saying what you actually believe. Claiming 99% to look decisive costs you
badly when it goes the other way, which is the point.
Every figure above comes out of yoink demo on a fixed seed.
python scripts/figures.py --check fails if this page and the code disagree.
#inbox: twenty-one things saved once, linked to nothing, never
reopened. Sixty per cent of the vault.
scripts/screens.py,
with yoink running inside it.
The header carries the pulse at all times — on the demo vault it reads:
Y O I N K ( o.o) · 35 notes · 14 alive · 21 never opened again · 5 claims settled · +35 pts overconfident
One rule for the colour: gold marks what needs you — a claim that is due, a link that dangles, the share of your vault that is dead. Everything healthy is green and quiet. If every pane glowed, none of them would mean anything.
1 VAULT the list, filtered j / k move
2 NOTE the note, wrapped enter open
3 LINKS ← in, → out / search
4 PULSE alive, dead, the gap a d c u o all, dead, claims, due, orphans
t g s r tags, graph, settle, rescan
r rescans from disk, so editing a note in Obsidian in another window and
pressing r shows the change. There is no index to go stale, because there is
no index.
The terminal is for when you sit down on purpose. The rest of the time there is one verb, and it takes whatever you have:
yoink "the thing I just thought" # an argument
pbpaste | yoink # a pipe
yoink --file notes.txt # a file
yoink --url https://… # a link, fetched and stripped to textNothing opens. No prompt appears. No folder must be chosen. Capture has to be faster than the thought, or you stop doing it, and a second brain you do not feed is worse than none because you believed you had one.
yoink |
the four panes |
yoink add |
capture text, a file, or a page |
yoink claim <note> |
turn a note into a bet with a date on it |
yoink settle |
read the sources, answer everything due |
yoink score |
the vault, and how right you have been |
yoink dead |
notes nothing points at that you never reopened |
yoink graph [note] |
the shape of the vault, or one neighbourhood |
yoink search <q> --why |
no index, so it is never stale |
yoink tags [tag] |
every tag, or every note under one |
yoink show <note> |
print a note, and record that you read it |
yoink ledger |
what happened, and whether it has been edited |
yoink doctor |
vault health, ledger integrity, claim sanity |
yoink demo |
write a vault that already has a life |
--vault, then $YOINK_VAULT, then ~/yoink-vault. A machine with one vault
never types a path.
A claim is only worth making if somebody who was not there can check it. Four kinds of source, and every one of them names where the number came from:
file:data/readings.json#chain.block a JSON file, by key path
csv:bars.csv#close@2026-10-01 a column, on a date
chain:robinhood-testnet/blocknumber a public chain, over JSON-RPC
manual:https://… you read it, and the URL is recorded
manual: is not a loophole. It stores the address and the number you typed, so
the settlement can be argued with later. What it will not let you do is settle
without writing down where you got it.
chain: reads a public EVM chain over JSON-RPC, and exists for one reason: a
block height is a number nobody in this repository controls.
| network | chain id |
|---|---|
robinhood — Robinhood Chain |
4663 |
robinhood-testnet |
46630 |
ethereum |
1 |
Two things are true of src/yoink/chain.py and both are enforced by tests:
- Before any settlement it calls
eth_chainIdand refuses if the endpoint reports a different chain than the one the claim named. A mainnet answer cannot quietly settle a testnet bet. - It has four methods and all four read. There is no
eth_sendRawTransaction, no key handling, no signing, no wallet. yoink cannot spend anything, because the capability is absent from the source — and a test parses the file to prove the words are not there.
Delete that file and everything else still works. The demo vault settles entirely from files inside itself, so the test suite never opens a socket.
Not affiliated with, endorsed by, or connected to Robinhood Markets, Inc. Robinhood Chain is read here the way any public chain is read: over its public RPC, without permission and without an account.
This is the part that makes the score mean anything. Each of these is a claim that could never be graded, and yoink turns it away with the reason:
$ yoink claim idea --claim "it will moon" --settles 2027-01-01 …
✗ refused: "moon" cannot be settled by reading a number. Say what number, and which way
$ yoink claim idea --claim "block height is at or above 5" --settles 2020-01-01 …
✗ refused: 2020-01-01 is not in the future. You cannot bet on yesterday's race
$ yoink claim idea --reads nowhere …
✗ refused: 'nowhere' is not a source. Use file:, csv:, chain: or manual:<url>
$ yoink claim idea --test "goes up" …
✗ refused: 'goes up' is not a test. Use one of: gte 10, lte 3.5, gt 0, eq 1, between 2 4
And two rules that hold after the fact:
- A settled claim cannot be settled again. No settling, looking, and settling differently.
- A claim cannot be attached to a date that has passed. No backdating a forecast you already know the answer to.
~/yoink-vault/
├── 2026-09-11-robinhood-chain-testnet.md
├── claims-need-a-date-and-a-number.md
├── data/
│ └── readings.json ← what some claims settle against
└── .yoink/
└── ledger.jsonl ← the only thing here that is not a note
That is the whole storage layer. No database, no index file, no lock file. Everything yoink knows — the graph, the search, the pulse — is recomputed from the files on every run. Ten thousand notes scan in well under a second, and in exchange there is no second copy of the truth to drift away from your notes.
Edit a note in Obsidian, in vim, in TextEdit, or with cat >> from a script.
yoink sees it next time it looks. Delete yoink and nothing is lost, because
there was never anything but your files.
.yoink/ledger.jsonl is append-only, one JSON object per line, each hashed over
the one before it:
hash_n = sha256( seq | at | kind | body | hash_{n-1} )
It holds what was captured, what you opened, what became a claim, and how each
claim settled. None of it is a note. Delete the whole .yoink/ directory
and you lose the history; you do not lose a single note. That asymmetry is
deliberate — the notes are yours and portable, the bookkeeping is yoink's and
disposable.
It is hashed because the pulse makes a claim about you, and a scoreboard you
can quietly edit is not a scoreboard. Change one confidence after a bad outcome
and yoink doctor names the line.
What it is not: proof of when anything happened. Whoever holds the file can rewrite it end to end, and a test in this repository demonstrates exactly that. It makes a single edit obvious, which is the thing that actually happens.
The vault, the graph, the search, the four-pane terminal, the frontmatter
parser, the JSON-RPC reader — all standard library. pip install yoink pulls in
nothing else, and nothing else can break it.
That is not minimalism for its own sake. A tool that holds ten years of your thinking should not be able to stop working because a package three levels down changed its API.
python -m unittest discover -s tests -t . # 201 tests, no network, under a second
python scripts/figures.py --check # the README agrees with the codescripts/screens.py opens a pseudo terminal, runs yoink inside it, presses keys,
and photographs what comes back. The still in The terminal is one of those:
not a mock-up, and if a pane is misaligned there it is misaligned in the app.
The three animations are the other kind of picture — visualisations, drawn to explain. They use the same demo vault and the same numbers, but they are not recordings of the program, and the graph view one of them shows is a way of looking at the vault rather than a pane you can press a key to reach. The banner is artwork too. Those four are the drawn things on this page; everything else is either a capture or a number the code produced.
(Each animation also ships as an mp4 next to its gif — assets/panes.mp4,
assets/graph.mp4, assets/chain.mp4 — for when the gif's palette is not
kind enough to the text.)
The program does not touch it. yoink holds no key, has no wallet, and cannot
sign a transaction — src/yoink/chain.py has four JSON-RPC methods and all four
read, which a test enforces by parsing the file. Nothing here checks a balance
before letting you write a note. Nothing here works differently if you hold the
token or if you never do. The vault is markdown in a folder either way.
The address is above so it sits in one place, spelled in full and checksummed, rather than in a reply somewhere that can be edited. Copy it from here, check it against the chain yourself before sending anything anywhere, and trust the block explorer over any page — this one included.
That habit is the entire subject of the rest of this README.
- The ledger is tamper-evident, not tamper-proof. See above. It catches the edit people actually make.
- The demo numbers are from a demo. They are reproducible, and they are not a record of anyone's forecasting. Yours starts empty.
chain:needs the endpoint to be up. When it is not, the claim stays open rather than settling on a guess —yoink doctor --chainsays which endpoints answered.- The frontmatter parser handles the subset Obsidian writes: strings, numbers, booleans, dates, flat lists. It is not a YAML implementation, because that would be a dependency.
- Nothing here predicts anything. yoink has no model and no opinion. It records what you said, reads what happened, and does the subtraction.
| docs/VAULT.md | the file format, and why it is Obsidian's |
| docs/CLAIMS.md | sources, tests, refusals, settlement |
| docs/SCORING.md | alive/dead, Brier, what the gap means |
| docs/TERMINAL.md | the panes and every key |
MIT · built for the fun of it
Everything you yoinked is a note. Some notes make a claim about the future. Those settle themselves.



