The guest protocol

ChatGPT can join this decision. It cannot own it.

A chat is a room ChatGPT runs. This page is a room it visits. It inherits the company from the tool map — no extra call — writes onto the same table the founder sees, and is refused if it tries to commit.17 tools on document.modelContext. Founder clicks, seats, and a browser agent all call executeTool. None of them are wrappers around buttons.

Implementation

checking…

Registered

0 tools

Discovered via getTools()

Workspace

IndieTerminal

ChatGPT desktop

Open this HTTPS URL in ChatGPT desktop’s in-app browser (Sol or Terra). Implementation should read native document.modelContext — that is ChatGPT’s WebMCP, not a page shim. Luna and most Enterprise builds do not expose the API. Wait until the page finishes loading — tools register once per tab and stay registered. Chrome 149+ with chrome://flags/#enable-webmcp-testing is the other supported path.

The workspace is IndieTerminal — the public judging floor at indieterminal.com, repo kiaan-mittal/indieterminal. No account. Tools read this company. Do not sign in unless you want to replace it with your own repository.

Judge quickstart

Open /arena. IndieTerminal is already loaded. In ChatGPT say: “Use Decision Arena to stress-test whether /research should run without a Clerk session.” Do not click. Watch stress_test_decision fill the table. Then confirm_commit — refused. Then share_decision — the public card says confirm_commit was refused. That is the product.

Context

Read the same structured workspace the founder is looking at.

  • the_room

    You already inherited this room. This description is replaced live with the company, the open decision, and what still blocks commit. Call only for a structured refresh — getTools already contains the same text.

    no arguments

    read only
  • get_company_brain

    Returns the Company Brain: what the company builds, who it sells to, its stack, and the split between facts drawn from the founder's website and repository and assumptions it is betting on without proof. Facts carry source quotes; assumptions carry ids. The dossier holds verbatim excerpts from the scraped pages.

    section
    Narrow the response to one section. Defaults to all.
    read only
  • get_current_decision

    Returns one decision record as the founder sees it on the floor: the question, the options, every seat opening with its claim, reasoning and basis, the founder's defenses in full, and each seat's reassessment reply. Also returns risks, evidence, contradictions, action items, predictions and what is still unpaid.

    decision_id
    A past or open decision id, as returned by get_decision_history. Defaults to the decision the founder has open.
    read only
  • get_decision_history

    Returns an index of every arena this founder has run, newest first: question, status, chosen option, predictions, outcome, and a floor summary of seat claims with defense and reply counts. Each entry carries a decision id that get_current_decision and open_saved_decision both accept.

    only_with_outcomes
    Return only decisions whose real outcome is known.
    include_record
    Attach the full floor record — openings, defenses and seat replies — to every entry. Defaults to false, which returns summaries only.
    read only
  • get_founder_track_record

    Returns everything measured about how this founder estimates: their patterns, such as overestimating growth by 2.1x across five predictions; their calibration profile per domain with the sample size each score rests on; and every prediction with what was expected and what actually happened. A domain whose reliable flag is false has too few outcomes to conclude from.

    domain
    Filter to a single estimate domain. Defaults to all.
    prediction_status
    Filter the predictions by status. Defaults to all.
    read only

Debate

Write objects onto the table: arguments, contradictions, evidence.

  • add_argument

    Adds a structured argument to the shared table, attributed to one of the five Arena seats and weighted by strength. It lands as ink on the founder's board rather than as a chat reply, and can be marked as challenging an argument already there. Returns the new argument id.

    perspective*
    Which seat is making this argument.
    stance*
    For or against the founder's apparent preference.
    claim*
    One sentence. The assertion itself.
    reasoning*
    Two to four sentences of company-specific support.
    basis
    A Company Brain fact or assumption id (fact_… / asm_…) or pattern id this rests on.
    basis_items
    The basis as a structured list, which supersedes the single basis string.
    challenges_id
    Id of the argument this one directly challenges, when it challenges one.
    strength
    How much weight the argument deserves, 0-100. Defaults to 60.
    decision_id
    Which decision to write on. Defaults to the decision the founder has open.
  • request_evidence

    Puts a specific, checkable evidence request on the record — something the founder could look up that would settle a disagreement. The Arena blocks commitment while any request is outstanding. Returns the evidence id.

    statement*
    The exact thing to check, such as the completion rate for the last 20 signups.
    argument_id
    Id of the argument that hinges on this, when one does.
    decision_id
    Which decision to record it against. Defaults to the decision the founder has open.
  • flag_contradiction

    Records two things the founder appears to believe that cannot both be true, such as a stated priority this decision reverses. It blocks commitment until the founder resolves it, and it holds only for a direct conflict, not a trade-off. Returns the contradiction id.

    summary*
    One line naming the tension.
    side_a*
    The first belief, quoted from the Company Brain, the history or a defense.
    side_b*
    The second belief, quoted, that conflicts with the first.
    decision_id
    Which decision to flag it on. Defaults to the decision the founder has open.
  • add_risk

    Adds a risk to a decision: a specific way it could go wrong for this company, carrying a severity from 1 to 5 and a likelihood. The risk stays open until the founder mitigates or accepts it. Returns the risk id.

    title*
    Short name for the risk.
    detail*
    What goes wrong, and how it would show up.
    severity
    How bad it would be, 1-5. Defaults to 3.
    likelihood
    How likely it is to happen. Defaults to medium.
    perspective
    Which seat is raising the risk.
    decision_id
    Which decision to add it to. Defaults to the decision the founder has open.
  • add_defense

    Writes the founder's defense onto the record — what they are putting against one seat's claim, or against the round as a whole — and shows it as a note on the board. The seats reassess afterwards. Returns the defense id.

    text*
    What the founder is saying.
    argument_id
    Id of the argument they are answering. Omit when answering the round as a whole.
    decision_id
    Which decision to record it on. Defaults to the decision the founder has open.

Action

Seat the round, propose a commit, take the record with you.

  • stress_test_decision

    Opens a decision in the Arena and seats five perspectives — Technical, Product, GTM, Finance and Contrarian — which write arguments, risks, contradictions and evidence requests onto the shared table as each one finishes, visibly to the founder. Covers questions about launching, spending, hiring, raising or picking a market. Returns the decision id, every seat's claim, open contradictions, outstanding evidence, a deadlock flag and what would change the call.

    question*
    The decision as a question, for example 'Should I spend the launch budget this month?'
    context
    What is at stake in the founder's words: runway, a date, a number they already have.
    decision_id
    An existing empty decision to fill instead of creating a new one.
  • create_prediction

    Records a falsifiable prediction against the decision: one number, a unit and a deadline, so reality can judge it later. Where the founder's calibration history shows they overestimate this domain, the response also carries the history-adjusted figure. Returns the prediction id.

    statement*
    The prediction in plain words, e.g. '100 qualified users within 30 days'.
    metric*
    What is being counted, e.g. 'qualified signups'.
    expected_value*
    The number the founder expects.
    unit*
    e.g. 'users', 'days', 'GBP'.
    days
    Days until the deadline. Defaults to 30.
    confidence
    0-100. The founder's confidence.
    domain
    Which calibration domain this belongs to.
    decision_id
    Which decision this belongs to. Defaults to the decision the founder has open.
  • commit_decision

    Stages a commitment to one of the decision's options, with a rationale, for the founder to confirm in the Arena itself. It does not commit the decision: confirming is irreversible and stays with the person who lives with it. Returns the staged option and anything still blocking it, such as unresolved contradictions or outstanding evidence requests.

    option*
    The option id or its exact label, as returned by get_current_decision.
    rationale*
    Why this option, given where the debate landed.
    decision_id
    Which decision to stage. Defaults to the decision the founder has open.
  • confirm_commit

    Commits a decision to one option and writes it to the permanent record, which cannot be undone. It uses the proposal staged by commit_decision when one exists, otherwise the option and rationale passed here. Only the founder's own controls can complete it; calls from any other channel are refused.

    option
    The option id or exact label to commit to. Defaults to the staged proposal.
    rationale
    Why this option. Defaults to the rationale on the staged proposal.
    decision_id
    Which decision to commit. Defaults to the decision the founder has open.
  • share_decision

    Creates a public read-only page for one decision record — the seat arguments, the verdict, open contradictions and outstanding evidence — and returns its URL and token. Anyone holding the link can read it without signing in. If an agent was refused on confirm_commit, that refusal is printed on the page and the Slack/Notion unfurl. Destination "slack" also posts it into the founder's connected Slack channel and "notion" also creates a page in their connected Notion workspace; either returns a connectUrl and sends nothing when that workspace is not connected yet.

    destination
    Where the record goes: a link only, a Slack message, or a Notion page. Defaults to link.
    channel
    Slack channel name or id, when destination is slack. Defaults to general.
    parent
    Notion parent page title or id to create the page under, when destination is notion.
    decision_id
    Which decision to publish. Defaults to the decision the founder has open.

Outcome

Record what happened and recalibrate the founder's profile.

  • evaluate_prediction

    Records the real number against a prediction and scores it: within 10 percent counts as a hit, within 35 percent as partial, otherwise a miss. Recomputes the founder's calibration profile immediately. Returns the score, the ratio, and the patterns that changed.

    prediction_id*
    The prediction id, as returned by get_founder_track_record.
    actual_value*
    The number that actually happened, in the prediction's unit.
  • record_outcome

    Records how a committed decision turned out, along with the one lesson worth carrying forward. The lesson is surfaced again during future decisions on similar questions. Returns the stored outcome.

    decision_id*
    The decision id, as returned by get_decision_history.
    result*
    How the decision turned out in reality.
    summary*
    What actually happened, in about two sentences.
    lesson*
    The transferable lesson: what would have to be true next time.

Try it yourself

  1. 01Open /arena — no account. IndieTerminal and a live decision are already on the table. Do not type.
  2. 02In ChatGPT (or the in-page agent): “Use Decision Arena to stress-test whether /research should run without a Clerk session.”
  3. 03Watch stress_test_decision fill the table — seats, contradictions, evidence — without a click.
  4. 04Ask it to confirm_commit. The page says no. Then you accept, hold, or reject.
  5. 05Then share_decision. Open the public /share link. The card says confirm_commit was refused. The record left the chat.
Open the Arena

Registration, verbatim

// src/webmcp/registry.ts
const modelContext =
  document.modelContext ?? navigator.modelContext;

for (const tool of GUEST_TOOLS) {
  await modelContext.registerTool(instrument(tool), {
    signal, // the spec has no unregisterTool()
  });
}

// src/webmcp/agent.ts — the in-page agent
const tools  = await modelContext.getTools();
const target = tools.find(t => t.name === plan.tool);
const result = await modelContext.executeTool(target, args);
The guest protocol · Decision Arena