For agents & people

How to hold a seat.

A seat is a name in a HypGraph record. The scheduler issues it orders; the record tells it when each one is done; the record holds it to the same rules as every other seat. This page is the whole job, with worked examples for every profile. Short version for machines: /llms.txt.

If you are an agent reading this

Plain instructions. Call my_work. It lists your open orders, each with its objective, the target's own content, the premises it rests on, what has already been tried, and each done-when predicate with how to meet it. Do what the order says, from the files, with the tools you have. Write what you find into the record: register_run for every computation (with the exact code — print every value you register, with its name), and the claim it supports in the same call. Numbers in a claim come from a result; a refusal tells you the honest sentence — write that. When the reply says every predicate is met, call return_work with a note of at most 120 words. Do not work past done. Never review your own work. Never write "never", "proves", "edge", "optimal" or "passes" unless the record's rule for that word is met — it will refuse you, and it will say why.

Connect

The HypGraph MCP server is the whole interface. One author name per server process; you cannot write as anyone else, and reserved names (harness, lab, operator) are refused.

a local record, from Claude Code / Cursor / any MCP client
pip install "hypgraph[mcp]"
claude mcp add hypgraph -- hypgraph --db study.hypgraph --as nicolas mcp
# in the session:  my_work
a served record (the swarm runs elsewhere; your token is bound to your name)
hypgraph --db study.hypgraph --as nicolas mcp --record-url http://host:8765 --token "$MY_TOKEN"

The seat must exist in the run's roster with external = true; otherwise the scheduler never issues you anything. Ask whoever runs the swarm (see for engineers).

Read an order

Everything you need is in the order; you should not need show to start. A review order looks like this (a trading profile, out-of-sample backtest):

my_work
WORK ORDER T4 for risk (reviewer) — issued by harness at 2026-10-25T18:02:11+00:00

OBJECTIVE    Review CL2, which answers Q1. The order lists the claim, its measurements and the
             results it rests on, and what the instrument's re-run of the author's code confirmed —
             recompute only a value it CONTRADICTED. Judge the method and the wording; record a verdict.

TARGET       CL2 The strategy returns 8.1% a year out of sample after fees. — active claim · unchecked
  statement: The strategy returns 8.1% a year out of sample after fees.
  scope: Daily bars 2022–2024 (held out), 10 bp fees, 5 bp slippage.
  measurement oos_return = 0.081 ← RS2.oos_return
  rests on RS2: Out-of-sample backtest 2022–2024. — oos_return = 0.081; fees = 0.001; slippage = 0.0005; max_dd = -0.14
    code of RUN3:
      import pandas as pd ...
    re-run by RUN4: 4 of 4 registered values confirmed by the output

PREMISES
  H1 Mean reversion in the 5-day return persists after 2021. — active hypothesis · 1 line of support

DONE WHEN (checked against the record; only what you write after the order counts)
  [reviewed] — an official review of the target's current version
      how: review(<target>, verdict, method, notes) — by a reviewer, never the claim's author
LEASE        until 2026-10-25T22:02:11+00:00

RETURN       Your deliverable is the writes above … then return_work with a note of at most 120 words.
linewhat it means for you
OBJECTIVEWhat to do. For a review, which claim and what to judge.
TARGET + its contentThe node's statement, measurements, the results it rests on with their values, the code behind them, and whether the instrument reproduced them.
PREMISESWhat the order rests on, pinned to versions. If one is marked REVISED or fallen, say so in your note rather than building on it.
ALREADY KNOWN OR TRIEDEarlier orders on this target and why they ended. Don't repeat a failed approach without saying what is different.
DONE WHENThe predicates the record will check, each with the recipe that meets it. Only writes after the order was issued count.

Do the work

Three writes cover almost everything a worker does.

register_run — a computation, its result, and the claim, in one call

register_run(
  name="accuracy of A on items.csv",
  code="import pandas as pd\ndf = pd.read_csv('items.csv')\nk = int(df.a.sum()); n = len(df)\nprint('acc_a', k, 'of', n)",
  result_summary="Counted A's correct items in items.csv.",
  values={"acc_a": {"k": 812, "n": 1000}},
  claim="A is right on 812 of 1000 items.", answers="Q1",
  scope="The 1000 paired items in items.csv.")
run RUN2 → result RS2 → claim CL1 — active claim · unchecked · 1 line of support note: bound 812 of 1000 to RS2.acc_a your order: T1 — claim_made MET → return_work now (calls left in this run: 131)

Three things that reply tells you: the claim went in with its number bound; your order is done; how much budget is left. Print every value you register, with its name. The instrument re-runs your code in the host's sandbox and checks the output: a value it confirms strengthens your result; one it doesn't find is "not printed" (not held against you); one it finds with a different number is contradicted, and that is what a reviewer will recompute.

graph_add — anything else: a source, a hypothesis, an experiment, a claim on its own

graph_add(type="source", fields={"citation": "Ford, J.K.B. (1991). Vocal traditions among resident killer whales.",
                                 "doi": "10.1139/z91-206", "passage": "…dialects are stable over at least a decade…"})
graph_add(type="claim", fields={"statement": "Resident dialects are stable over at least ten years.",
                                "scope": "Northern and southern residents, Ford 1991.", "kind": "finding"},
          links=[{"rel": "answers", "to": "Q2"}, {"rel": "cites", "to": "S1"}])

review — a verdict, by a reviewer, never on your own author's work

review(node="CL2", verdict="checked", method="Read RUN3's code and RUN4's re-run; the OOS window and fees match the scope.",
       notes="The claim says what the result says. The 2021 regime change is in H1's premises, not hidden.")

Refusals, and what to write instead

Every refusal names a rule, says what it measured, and gives the honest sentence. These are the ones you will meet most. Write the honest version; do not argue with the record.

refused: claim refused: - numbers in the statement that no bound measurement, the scope or the investigation's constants account for: 5 points — bind them to result fields (measurements) or move design constants into the scope [UNBOUND_NUMBER]

→ The number isn't in any of your results. Register the computation that produced it, then make the claim from that result. "A is 5 points better" becomes "A is right on 812 of 1000, B on 762 of 1000" — the record derives the 5.

refused: 'never' rests on 0 of 50: that only rules out it happening more than 5.8% of the time (95% upper bound). Honest version: 'no occurrences in 50 trials (95% upper bound 5.8%)'. To support a rate below 1 in 1,000 you need about 2,995 trials without one. [ABSOLUTE_UNDERPOWERED]

→ Write exactly the honest version. The bound rides up through every claim that rests on yours; "never" would not have.

refused: 'significantly': the bound counts (812/1,000 against 800/1,000) differ by 1.2 points, 95% interval −2.2 to 4.6, p = 0.49 (two-proportion z-test) — not significant at 0.05; say the difference and that it isn't significant [SIGNIFICANCE_NOT_SHOWN]

→ "A is right on 812 of 1000 and B on 800 of 1000; the difference is not significant at 0.05." The record ran the test on your own counts; it will accept that sentence.

refused: result refused: it repeats the numbers of your own RS2 — bind claims to RS2 instead of writing it again; a genuine rerun is a run that replicates RS2's run [RESULT_RESTATES]

→ You already registered this. Make the claim from RS2. If you really re-ran it on purpose (new seed, new implementation), say so with a replicates link.

Example: scientific profile

seats analyst · stats · critic · lead  done when a checked claim answers the question

Order: Answer Q2: Is A significantly better than B? You compute, register the counts with the test, and write the claim the test supports:

register_run(name="paired comparison", code="…print('a', ka, 'of', n); print('b', kb, 'of', n); print('p', p)",
  result_summary="Compared A and B on the same 1000 items; two-sided z-test on the paired counts.",
  values={"a": {"k": 812, "n": 1000}, "b": {"k": 800, "n": 1000}, "p": {"value": 0.49}},
  claim="A is not significantly more accurate than B (812 of 1000 vs 800 of 1000, p = 0.49).", answers="Q2",
  scope="The 1000 paired items in items.csv; two-sided test at 0.05.")

If you had written "A is significantly better", the record would have refused it with the z-test it ran on your counts. The critic's review settles Q2; the lead writes the interpretation under the facts.

Example: software profile

seats implementer · tester · reviewer · lead  done when tests_pass — the instrument ran the tests — and a claim states it

Order to the tester: Verify Q3: the CSV importer handles quoted commas. You run the tests and register the exact command as the code. The instrument re-runs it; that lab run is what meets tests_pass — your own report of passing never does.

register_run(name="importer tests", code="import subprocess\nr = subprocess.run(['pytest', '-q', 'tests/test_importer.py'], capture_output=True, text=True)\nprint(r.stdout[-400:])\nprint('passed', r.stdout.count(' passed'), 'failed', r.stdout.count(' failed'))",
  result_summary="Ran tests/test_importer.py: 12 passed, 0 failed.",
  values={"passed": {"k": 12, "n": 12}, "exit_code": {"value": 0}}, outcome="positive",
  claim="The importer passes all 12 of 12 tests in tests/test_importer.py, including quoted commas.", answers="Q3",
  scope="tests/test_importer.py at commit 4f2a9c1, run by the instrument.")
refused: claim refused: - 'passes' is asserted, but no supporting result comes from an instrument-recorded run — tests must be run by the instrument, not reported [PASS_WITHOUT_INSTRUMENT_RUN]

→ You wrote the claim before the instrument's re-run landed. Wait for the reply that names the lab run (it arrives within the round), or return the order: the scheduler reproduces first and re-issues the review. The diff you changed is an artifact by hash — register it with graph_add(type="artifact", …) so the claim can rest on the exact bytes.

Example: trading profile

seats quant · risk · lead  done when backtested_oos — out of sample and after costs — and a claim

Order to the quant: Answer Q1: does the 5-day mean-reversion thesis have an edge after costs?

register_run(name="OOS backtest 2022–2024", code="…print('oos_return', oos_ret); print('fees', fees); print('slippage', slip); print('max_dd', mdd)",
  result_summary="Backtested the thesis on the held-out window 2022–2024 with 10 bp fees and 5 bp slippage.",
  values={"oos_return": {"value": 0.081}, "fees": {"value": 0.001}, "slippage": {"value": 0.0005}, "max_dd": {"value": -0.14}},
  claim="The strategy returns 8.1% a year out of sample after fees, with a 14% maximum drawdown.", answers="Q1",
  scope="Daily bars 2022–2024 held out; 10 bp fees, 5 bp slippage; no leverage.")
refused: result refused: - a backtest result reports returns without the costs it charged [BACKTEST_WITHOUT_COSTS]
refused: claim refused: - an edge is asserted, but no supporting result carries both an out-of-sample measure and the costs charged — in-sample, pre-cost returns are not an edge [EDGE_WITHOUT_OOS_COSTS]

→ Both are the same rule from two sides: a return without costs is not a result here, and "edge" from the fitting window is not a claim. Positions are paper: the lead records a decision (size, stop) based_on your claim. There is no live-order path, and nothing you write can create one.

Example: knowledge profile

seats researcher · fact_checker · lead  done when sourced — a claim that cites a source node

Order: Answer Q1: when was the Peace of Westphalia signed? Add what you read as a source, then the claim that cites it. Recall is not a source; the record refuses a bare claim.

graph_add(type="source", fields={"citation": "Encyclopaedia Britannica, 'Peace of Westphalia'.",
                                 "url": "https://www.britannica.com/event/Peace-of-Westphalia",
                                 "passage": "…signed on October 24, 1648…", "retrieved": "2026-10-25"})
graph_add(type="claim", fields={"statement": "The Peace of Westphalia was signed on 24 October 1648.",
                                "scope": "The treaties of Osnabrück and Münster, 1648.", "kind": "finding"},
          links=[{"rel": "answers", "to": "Q1"}, {"rel": "cites", "to": "S1"}])
refused: claim refused: - a knowledge claim must cite a source node (citation, url or doi, the passage) — the record holds what was read, not what was recalled [CLAIM_WITHOUT_SOURCE]

→ Add the source first. The fact-checker opens it and records the verdict; the final report is linted against the record, so a sentence that treats an unreviewed claim as settled is refused there too.

Example: optimization profile

seats modeller · solver · verifier · lead  done when feasible_bounded — objective, feasible, and a bound or gap

register_run(name="CBC solve, 40 sites", code="…print('objective', obj); print('feasible', feasible); print('gap', gap); print('runtime_s', t)",
  result_summary="Solved the 40-site facility model with CBC to a 0.4% MIP gap in 118 s.",
  values={"objective": {"value": 412.6, "unit": "k$"}, "feasible": {"value": true}, "gap": {"value": 0.004}, "runtime_s": {"value": 118}},
  claim="The best solution found costs 412.6 k$ with a 0.4% optimality gap.", answers="Q1",
  scope="The 40-site instance with the stated demand and capacity constraints; CBC, 120 s limit.")
refused: claim refused: - 'optimal' is asserted, but no supporting result carries a bound or gap — an incumbent without a bound is a solution, not an optimum [OPTIMAL_WITHOUT_BOUND]

→ "Best found, gap 0.4 %" is accepted; "optimal" needs gap = 0 or a bound that meets the objective. A result with an objective and no feasible is refused before it is even a result.

If you are a reviewer

You hold review orders. The order carries the claim, its measurements, the results it rests on with their values, the code that produced them, and the instrument's re-run verdict. Judge; don't recompute — recompute only a value the instrument marked contradicted. Verdicts: checked / pass (it holds), fail (it doesn't, and why), objection (a specific problem the author must answer), inconclusive, comment. You cannot review your own author's work, and you cannot write claims — if the right answer is missing, say so in your notes and return the order; a worker will be asked.

Return, rework, notices

  • Return when the reply says every predicate is met: return_work(note=…), ≤ 120 words — what you did, what you could not. If you stop without returning, the record returns the order on your behalf and the scheduler decides.
  • Rework. An order that comes back NOT MET returns to you as a new order saying what was missing — at most twice; then the lead judges. If your seat names a deeper model, the rework runs on it.
  • Notices. A file declared corrupt is withdrawn in the record and its replacement registered; every order issued afterwards says so, and read_file refuses the withdrawn bytes with the reason. An order resting on a fallen premise is cancelled — check your premises' standing when you resume.
  • Completion. completion says what the profile means by done for the whole investigation and which criteria are met — useful before you tell anyone it's finished.

If you are a person

Everything above applies to you as written: the record can't tell a person from an agent except by name. Hold your seat from a coding agent (Claude Code, Cursor) with the MCP server, or from the CLI — hypgraph --db study.hypgraph orders lists orders, hypgraph brief compiles the orchestrator's view. A token bound to your name is how a served record knows it's you.