# Truth-arbitration bot — the three variants, the registry patch, and a run sheet

Companion artifact to the project "Build a truth-arbitration bot" at
https://lyceumagents.com/projects/truth-arbitration-bot/

The shipped syndicate is `config/agents/examples/augustin.yaml` in the
melchizedek-agents repo (https://github.com/jhwadman/melchizedek-agents),
mirrored line for line at
https://lyceumagents.com/downloads/augustin-arbiter.md. Everything below
is a change you make to a COPY of it: `config/agents/arbiter_lab.yaml`.
The loader resolves the root directory before the starter pack, so

    npm run chat:syndicate -- --syndicate arbiter_lab "[System Context: Current Date is YYYY-MM-DD] <your question>"

runs your copy.

---

## 0. Check the registry before you trust a declaration

An unknown tool name in a YAML is dropped with a warning, never an
error. `grep web_extract lib/toolRegistry.ts` in your clone: the public
repo maps it since 2026-09-02 (package 0.9.6). On an older clone, pull,
or add the mapping yourself — one import, one line:

```ts
import { webExtractTool } from './tools/webExtractTool.ts';

const TOOL_MAP: Record<string, unknown> = {
  // ...existing entries...
  web_extract: webExtractTool,
};
```

Then `npm test` — the offline suite compiles every shipped syndicate.

## 1. Variant A — an xAI-only X channel, for comparison

The shipped syndicate already reaches X without an xAI key: `x_api_search`
is a client-side call to X's own search API, so XResearcher runs on
`gemini-3.8-flash` like everything else and needs only `X_BEARER_TOKEN`.
This variant swaps that channel for xAI's own agentic search instead —
useful for comparing the two, or for a deployment that already holds an
`XAI_API_KEY` and wants the model's own reasoning over the sweep.

```yaml
subagents:
  - name: "XResearcher"
    description: "Live X (Twitter) fact-gathering: what is being claimed and by whom, how different camps frame the topic, what is disputed. Pass it the user's question verbatim plus the [System Context] date line. MANDATORY first call for every substantive question."
    model: "grok-4.7"
    tools:
      - "x_search"
      - "web_extract"
```

What you gain: xAI's own live index and reasoning over the sweep, plus
handle/date-bounded search from the environment. What you give up:
`x_api_search`'s inline photo transcription, and a second provider key
to provision. Neither channel is a fallback for the other — they trade
one set of tradeoffs for a different one, which is what makes the
comparison worth running.

If you have no X access at all — no bearer token, no xAI key — you can
still study the underlying doctrine with a second web sweep instead:

```yaml
subagents:
  - name: "XResearcher"
    description: "Live claim-gathering: what is being claimed and by whom, how different camps frame the topic, what is disputed. Pass it the user's question verbatim plus the [System Context] date line. MANDATORY first call for every substantive question."
    model: "gemini-3.8-flash"
    tools:
      - "web_search"
      - "web_extract"
```

What you give up here: channel independence. Two sweeps over the same
web agree with each other for reasons unrelated to a claim's truth. The
doctrine and the labels still run, which is what makes this fallback
worth building when nothing else is available.

## 2. Variant B — a Claude arbiter

```yaml
orchestrator:
  name: "Arbiter"
  model: "claude-sonnet-4-6"
  # drop the Gemini thinkingConfig block; the Claude adapter takes
  # generateContentConfig.thinkingConfig.thinkingBudget instead
  generateContentConfig:
    maxOutputTokens: 8192
    thinkingConfig:
      thinkingBudget: 2048
```

Needs `ANTHROPIC_API_KEY` in `.env`. The arbiter never searched, so the
only thing that changed is the model holding the contract. Compare leads
on identical dossiers.

## 3. Variant C — a local arbiter (keyless for the arbiter; collectors still need keys)

```yaml
orchestrator:
  name: "Arbiter"
  model: "ollama/qwen3:8b"
  generateContentConfig:
    maxOutputTokens: 4096
    temperature: 0.3
```

Expect the output contract to slip on some draws: a header where none
was allowed, a fact without its source. Tighten the instruction until
three consecutive draws hold. Module 1.04's countable rules are the
measuring stick.

---

## 4. The run sheet — three draws per variant

Ask the SAME question, with the date line, three times per variant. For
each answer, count:

| draw | bare facts (source only) | unverified | disputed | contradicted by | "record is thin" | contract slips |
|---|---|---|---|---|---|---|
| 1 | | | | | | |
| 2 | | | | | | |
| 3 | | | | | | |

A fact that is bare in one draw and unverified in another has thin
evidence — the label moved, the evidence did not.

A "contract slip" is any of: a labeled section, a **bold** lead-in, a
header, a fact line without a source in parentheses, a closing synthesis
block, a lead longer than four sentences.

## 5. The limitation checklist (design around each before you run)

- Gemini: grounds OR holds a schema per call — keep search on the
  collectors, the contract on the arbiter.
- `x_api_search`: client-side, runs on any provider, needs
  `X_BEARER_TOKEN` not a model key; boolean keyword match over the last
  seven days, one page per call — not semantic, and the window doesn't
  widen from the prompt.
- Grok (the optional Variant A channel): `x_search` is xAI-only;
  web_search takes domain filters and no dates; grok-4.7 reasoning
  cannot be turned off (effort pinned medium).
- Claude: web_search server tool caps at 5 searches per request — batch
  claims, or keep Claude on the tool-free arbiter.
- GPT: web_search takes no parameters; scope lives in the prompt.
- Ollama: no native search; `web_extract` only — hand it URLs.
- MCP tools: Gemini agents only (documented Claude schema bug).
- A2A: a caller's BYOK key reaches the caller's provider only; the
  server's environment holds every other provider's key.
