Skip to content

When Two Agents Talk Directly: Designing Bounded Bull–Bear Research ​

Multi-Agent Investment Research · Part Two | Why a genuine challenger matters, and what it takes to make the exchange real

Investors rarely lack reasons to like an investment. After a sector rallies, reports, social posts and product descriptions can all explain why it has a promising future. Ask an AI assistant for another analysis, and it may collect even more arguments in favor.

But before changing a portfolio, a more valuable question is often: What if my strongest reason is wrong? Who will examine it seriously instead of agreeing with me?

That is why we added bull–bear research to ETF Agent. “Bull” and “Bear” here are research responsibilities, not instructions to open long or short positions. One researcher constructs a supporting case; the other looks for evidence that could invalidate it.

The engineering problem comes next. If they are to question and answer one another, the application must know exactly who spoke, who received each statement, and what actually happened after a model call was interrupted. A server restart must not invent a debate that never took place.

We will begin with the investor’s problem, then go deeper into the protocol and the recovery failures we encountered.

1. A Report with Both Sides Can Still Miss the Point ​

Imagine an investor moving ten percentage points of the total portfolio into a technology ETF. The stated reason is: “Owning one more fund should make my portfolio more diversified.”

A conventional analysis might offer two columns. The bullish side discusses technological growth and product characteristics. The bearish side lists valuation risk, volatility and concentration. That is more balanced than a sales pitch, but the crucial fact may still go unchecked: the new fund could own many of the same underlying assets as existing funds.

Unless someone asks the bullish researcher to defend the connection between “more funds” and “more diversification,” the two sides may simply talk past each other.

We wanted targeted falsification: identify a stated premise, seek information that would materially change it, and give the original advocate a chance to respond to the specific evidence.

For investors, this could help before a purchase, during a review of a months-old thesis, or whenever a team needs to preserve a genuine disagreement rather than only a polished conclusion. These are intended research benefits. They are not measured improvements in investment returns.

2. Two Independent Reports Are Not a Conversation ​

We considered three patterns:

PatternWhat the investor receivesWhen it helps
Parallel analysisOne bullish report and one bearish reportBroadly understanding an investment
Main-mediated follow-upMain relays questions after reading both reportsOccasional clarifications without a peer protocol
Direct peer dialogueBear challenges a specific Bull claim, and Bull receives and answers itImportant premises that deserve sustained scrutiny

“Direct” does not mean the language models establish a private network connection. The application still transports the message. The difference is that Main does not rewrite each statement or consume an additional model turn merely to relay it.

Even so, the third approach is not always better. A straightforward fee comparison may need just one researcher. Peer dialogue consumes time, model requests and a shared research budget. With no meaningful disagreement to explore, extra rounds produce noise.

We therefore did not turn every financial query into a mandatory bull–bear committee. Main may opt in when there is value, while respecting explicit user requests or exclusions. A dialogue can also end as soon as it stops adding useful information.

3. A Good Bear Can Say: “I Found No Strong Counterexample” ​

Bull is responsible for supporting an argument; Bear is responsible for actively testing it. They are not obliged to be permanently optimistic or pessimistic.

Bear should present at most three substantial, qualified challenges. That is a ceiling, not a quota. If none can be established, it should describe what it checked and what remains unknown.

Bull need not “win,” either. It may withdraw an unsupported premise while keeping other open questions alive.

Here is a synthetic teaching exchange, not a transcript from an actual model run:

Bull: Adding a technology ETF may create new growth exposure, but we need to compare its holdings with the existing portfolio before claiming improved diversification.

Bear: On the stated look-through assumptions, technology exposure rises from 15% to 23%. More fund names therefore do not establish greater diversification. This calculation alone does not establish the direction of total portfolio volatility.

Bull: I withdraw the argument that adding a fund automatically improves diversification. If the goal is to increase technology exposure intentionally, we need a different rationale and must examine valuation, cash use and risk tolerance.

The conversation has not decided whether to buy. It has made one weak premise visible and correctable.

For investment research, that is more useful than letting a third model vote on the winner. Two agents repeating the same source do not create two independent pieces of evidence.

4. The Product Should Show Real Disagreement, Not a Performance ​

We want the investor to be able to answer three questions: what was originally claimed; what was actually challenged, answered or revised; and what remains unresolved.

For example, a rise in technology-sector weight does not mechanically prove a rise in total portfolio volatility. Correlations, funding source and investment horizon still matter. The final report must preserve the scope of what the evidence supports.

There is also false transparency to avoid: a screen that displays alternating Bull and Bear bubbles even though Main wrote the entire dialogue in one pass. If we claim that two separate agents talked, their independent statements and actual delivery path must be traceable.

That turns a product requirement into a runtime question: How can we prove that the exchange happened without letting it block ordinary research?

5. The Protocol: Independent Openings Before Bounded Exchange ​

ETF Agent already had a Main/Child model. Main owns the final user-facing answer; a Child can research and use permitted tools within a separate execution context. We reused this existing execution mechanism instead of building two special-purpose agent runtimes.

Each Child begins with the original question and its own authorized facts. It produces an independently authored, public opening. An opening is neither hidden chain-of-thought nor a raw tool trace. Only after both valid openings are available can the actual exchange begin.

Pair formation also has two steps. The first Child proposes a peer offer and stops at a safe point; the second joins using the original issued task identity. The application checks their shared Root, complementary roles and authorizations, then freezes the pair identity. Otherwise the first Child might finish before its alleged counterpart even exists.

The message belongs to the existing Child lifecycle owner, not to a separate debate service. The simplified path is:

The message belongs to the existing Child lifecycle owner, not to a separate debate service. The simplified path is:

sequenceDiagram
    participant Bear as Bear Child
    participant Host as Execution and authorization
    participant Store as Durable records
    participant Bull as Bull Child
    Bear->>Host: Propose challenge and evidence references
    Host->>Host: Validate pair, round and source access
    alt Invalid
        Host-->>Bear: Reject this send and report the gap
    else Valid
        Host->>Store: Store unique message and receipt
        Store-->>Host: Return original message identity
        Host-->>Bear: Accepted; safe to wait
        Host-->>Bull: Send deduplicated wake hint
        Bull->>Host: Request continuation
        Host->>Store: Read original message and cursor
        alt Root may continue
            Host->>Bull: Include original message in next model request
            Bull->>Host: Submit linked response
        else Stopped or expired
            Host-->>Bull: End peer work; retain existing results
        end
    end
Architecture diagram

Main does not paraphrase every round. Neither Child gains new trading, source or budget authority simply by being part of a pair.

6. “Sent” Is Not One Boolean ​

There are three distinct facts.

First, the model proposes a message. Bear asks to challenge something.

Second, the application accepts the send. It checks authorization and dialogue state, then durably records the unique message and receipt.

Third, Bull’s next actual model request includes that exact message. Only then can we say the message was delivered into the recipient’s model input.

Even the third fact does not show that the model understood the challenge or that the challenge is correct. Financial evidence has the same distinction: a citation exists; the model saw it; and the source actually supports the conclusion are different claims.

A message needs identity tying together its author, recipient, pair, causal round, original reply and source lineage. This is an illustrative shape; production also checks sealed model requests, tool receipts and authorizations:

ts
type PeerMessage = {
  messageId: string;
  pairId: string;
  senderExecutionId: string;
  recipientExecutionId: string;
  round: number;
  replyTo?: string;
  text: string;
  evidenceRefs: string[];
};

The recipient comes from the frozen valid pair, not an arbitrary address chosen by the model. The reply references an actual message ID, not a guess based on wording.

We keep these facts within the original execution receipt system. Creating a second “truth” database for the debate would make recovery and audit harder, not safer.

7. Dialogue Needs an Ending: Rounds, Waiting and Budgets ​

We deliberately did not implement “continue until both agents agree.”

A round contains one challenge or proposition and at most one causally linked response. The independent openings are not counted. An occupied half-round cannot be retried for free after recovery. Bear starts the first challenge, Bull responds, and further exchange is optional.

The legal maximum is determined by the trusted platform limit and any valid one-time user request; it is frozen with the pair. A round allowance does not create extra model budget. Existing Root and Child limits, deadlines, cancellation and finalization still apply.

The legal maximum is determined by the trusted platform limit and any valid one-time user request; it is frozen with the pair. A round allowance does not create extra model budget.

flowchart TD
    A[Both Children submit independent openings] --> B{Useful to continue and still authorized?}
    B -- No --> H[End dialogue and return existing findings]
    B -- Yes --> C[Submit an actual challenge]
    C --> D[Persist state and release execution slot]
    D --> E{Valid reply or terminal event?}
    E -- Reply --> F[Resume under the same execution identity]
    F --> B
    E -- Terminal --> H
    H --> I[Main synthesizes disputes and gaps]
Architecture diagram

Waiting does not mean keeping a server thread busy or polling forever. A Child can park at a safe point, yielding its execution permit, and wake on a relevant durable event. Existing resource governance decides which reservations remain.

One subtle race occurs when a reply arrives between “there is no message yet” and “register this waiter.” The waiter and message check need a coherent durable convention. A notification is a hint to inspect the original facts, not the facts themselves.

8. The Difficult Part Was Recovery, Not Eloquence ​

A useful failure test stops the process at an awkward moment: the message has been saved, but the recipient has not consumed it.

Crash boundaryWhat is establishedSafe recovery behavior
Before send commitsProposal exists; no accepted receiptDo not invent a successful send
After commit, before notificationOne durable message receipt existsWake for that message; do not create another
Request sealed, dispatch outcome unknownRequest identity exists; external effect unknownPreserve uncertainty; do not assume replay is safe
Recipient request actually submittedMessage entered a real model requestPreserve its consumption identity and round debit

This is idempotency: retrying the same operation must not duplicate its business effect. Message identity must bind the actual sending action, not only a text hash; identical words in two rounds can be two distinct acts. Nor can an external model provider always guarantee exactly-once dispatch after a crash. [1]

Real failure: the notification arrived, but recovery failed ​

In an isolated PostgreSQL recovery exercise, the waiting state was persisted and a wake notification arrived. Yet a second operating-system worker failed to take over.

There were two issues. The test helper had not supplied the original durable wake input. Separately, an authorization identity that had passed through PostgreSQL was compared as a JSON string. PostgreSQL jsonb does not preserve object-key order, so logically identical authorization objects could be rejected merely because their keys were serialized differently. [2]

We repaired the actual wake path and used structural comparison for the logical authorization object while still rejecting genuinely different identities. That does not justify loosening exact comparison everywhere: sealed model-input bytes and signatures have their own identity requirements.

Notification delivered does not equal task recovered. Equal-looking data does not imply a correct identity check.

Real failure: the words arrived, but provenance became “unknown” ​

Another issue appeared when a public peer message reached downstream processing, but its original source identity could not be reused by a subsequent computation.

The model-facing projection intentionally omitted some Host-only source IDs. A later check mistakenly compared that shortened view with a complete internal receipt. The fix was to verify which original record produced the shortened view, then consult the canonical receipt for legally usable provenance—not fill empty fields with “verified.”

In financial research this distinction matters enormously. A citation visible in the interface does not mean that its underlying protected data may be reused by another Child.

9. Peer Messages Never Grant Data or Trading Authority ​

Financial data has different access scopes. If Bear may read protected account material but Bull may not, converting a number from that material into a sentence does not automatically make the sentence public.

We examine both the referenced identifiers and the provenance of the complete outgoing text. When lawful sharing cannot be established, only that send is refused and the gap is recorded. We do not pretend that a few regular-expression replacements can safely sanitize arbitrary sensitive reasoning. Bear may still hand its lawful findings back to Main.

Likewise, a peer saying “execute this trade” remains model-authored opinion. It cannot become a user instruction or expand tool, source, budget or account-write authority.

Peer opinions may influence one another; they must not rewrite one another’s permissions.

Main ultimately synthesizes the evidence without automatic arbitration or majority voting. Averaging a proposed 10% buy and a proposed 0% buy into a 5% order would not resolve a missing covariance estimate or an unconfirmed cash requirement.

10. An Optional Tool for Difficult Questions, Not a Ritual ​

As of October 24, 2026, bounded peer dialogue had passed scoped engineering acceptance: independent openings, actual causal questions and replies, durable receipts, safe waiting and cold recovery, and links to original investment-thesis records. Limited real-model exchange was observed. This does not establish production deployment or comparative financial-research quality. Real observations also showed cost and wording limitations.

Our choice was to preserve direct dialogue for material hypotheses worth challenging, while allowing simpler research to remain simple. If a participant fails, Main can still deliver legitimate work already completed, with the missing pieces disclosed.

The point of a Bull–Bear Agent is not fiercer disagreement. It is to let a specific argument be challenged, answered and revised—and to keep that evidence accessible even after the process fails.


Sources and further reading ​

[1] AWS Builders’ Library, Making retries safe with idempotent APIs. The design principle does not imply that model providers offer identical guarantees.

[2] PostgreSQL, JSON Types. Logical JSON object identity must not be confused with byte-for-byte string identity.

For the foundation, see Subagents: from context isolation to specialized collaboration. Next: Investment research, multiple perspectives, and falsifiable theses. Explore the ETF Agent article collection; Stars are welcome.

Engineering notes, evidence and boundaries.