Agentic Trading
Decisions

ADR-0006: Trading agent and chat agent are separate processes sharing one Skill identity

  • Status: accepted
  • Date: 2026-05-27
  • Refined by: ADR-0019 — the trading-vs-chat split stands (chat still has no order-placing tools), but chat is no longer a per-deployment agent that shares one Skill's identity. It is now one product-wide, user-scoped agent with its own brand persona, capable of authoring, coaching, and preparing actions across all the user's deployments.

Context

The deployer needs to ask their running agent natural-language questions about its decisions, risks, news context, etc. This is fundamentally different from the agent's trading loop:

PropertyTradingChat
TriggerSchedule (cron/event)Per deployer message
Side effects allowedPlace ordersNone
LifetimeLong-running (Fly machine)Per-request (Vercel Function)
Latency sensitivityTick interval (seconds–minutes)Conversational (sub-second tokens)
ConcurrencyStrictly serial per SkillMultiple sessions OK

Putting both in one process means:

  • Slow chat sessions can delay ticks (or vice versa)
  • The same code path must handle both modes
  • The chat agent inheriting propose_order is a real safety risk

Decision

Two separate agent instances per Skill, sharing the same Skill identity (system prompt, model, persona):

  1. Trading Agent — runs in the Fly live-runner process, on the Skill's schedule. Has propose_order and other write-capable tools.
  2. Chat Agent — runs in a Vercel Function, per HTTP request. Has read-only tools + introspection tools. Cannot place orders.

Both call generateText/streamText with the same Skill system prompt (the chat agent's prompt has a short introspection addendum). Same Skill identity, different responsibilities.

Alternatives considered

Alt A — Single agent process handling both ticks and chat

  • One identity, one code path
  • Chat blocks ticks, ticks block chat
  • Chat agent gets propose_order and could be prompt-injected into placing an order
  • Not picked: resource contention + safety regression. Worse on every dimension that matters.

Alt B — Chat as a non-agent service (templates over snapshots)

  • Pre-template common questions ("why did you trade?" → render snapshot reasoning)
  • Cheap, deterministic
  • Loses the conversational flexibility users actually want
  • Not picked: misses the product value. If the answer is a templated render, why bother with chat UX?

Alt C — One agent, but with mode-conditional tools

  • Same process, but mode parameter switches the tool whitelist
  • Still has resource contention (single process serving both)
  • Still risks tool-list bugs leaking write tools to chat
  • Not picked: minor benefit, real risk.

Consequences

Positive

  • No resource contention — chat sessions can't delay ticks
  • Safety boundary at the process level — the chat agent literally cannot place an order; its process doesn't have those tools loaded and its broker handle is null
  • Independent scaling — chat is per-request HTTP, scales with web traffic; trading is per-Skill VM, scales with deployment count
  • Cleaner cost model — chat costs attributed to chat usage; trading costs attributed to trading
  • Different latency budgets — chat optimizes for first-token-fast (streaming); trading optimizes for tick-on-schedule (cron)

Negative / trade-offs

  • Two code paths to maintain (mitigated: both use the same packages/agent-runtime primitives and the same packages/tools registry with different whitelists)
  • The chat agent doesn't have access to the trading agent's in-memory state — it reads everything from agent_state + decision_snapshots. This means very fresh state (current tick in flight) may not yet be visible to chat. Acceptable.
  • Slight context-window inefficiency: each chat turn re-reads snapshots that the trading agent already has in memory. Cache-control + summary-first tools mitigate.

Things we'll need to revisit

  • If we add conversational command ("flatten my position" via chat with confirmation), the architecture stays the same — the chat agent surfaces a confirmation UI, the user clicks, the web app inserts an agent_commands row. Chat agent itself still has no command-issuing tool.
  • If we ever want the trading agent to remember conversations with the deployer (e.g., "I told you last week to be more conservative"), introduce a shared "deployer context" the trading agent reads. The split still holds.

References

On this page