brain/knowledge/decisions/000027-an-agent-is-a-project-scoped-row-that-flow-steps-reference-live.md
An agent row holds instructions, tools, model, max steps and structured output. A Run Agent step
stores only agentId and the server resolves the config at run start, so editing an agent changes the
next run of every flow linking it with no republish. Detach & customise copies the config inline
and clears agentId for steps that must differ.
Agreed 2026-08-12. The runtime already reads tools off the job payload rather than the flow version,
and flow_version.agentIds + extractAgentIds survive from the deleted 2025 agents module — so a
live reference costs no worker change and "which flows use this agent" comes free. Project scope
follows the tools: flow tools resolve by projectId and connections match on
ArrayContains([projectId]), so a platform-scoped agent would rebuild project scoping inside the row.
The point of naming an agent is to improve it once. A snapshot lets every flow drift independently and turns "make the agent better" back into per-flow editing — the pain the feature exists to remove. The rejected alternative was exactly that: dropdown prefills the step, link then gone.
WRITE_AGENT gates it, the edit is audit-logged, and the
editor shows "Used in N flows" before saving. If too weak in practice, the next move is a per-agent
"allow unattended writes" flag, not re-litigating the reference.externalId on the row from day one; project state must upsert
agents by (projectId, externalId), and until it does the import must fail loudly.agent, agent_run) from the 2025 module are dropped so the entity can take
the obvious name. breaking = true for rollback safety, no ⛓️💥 breaking-change label.AgentRunSource, not a nullable-agentId check: every gate
already branches on source, and it keeps agent conversations out of the Chat list for free. Unlike
a flow step it is attended — taint starts false and approval must not auto-decline.