Skip to content

Multiple agents sharing a project root run every Cue subscription N times — no way to designate an owner #867

@scriptease

Description

@scriptease

Summary

When two or more Maestro agents are registered against the same project directory, they each independently load the project's .maestro/cue.yaml and each spin up their own copy of every subscription. The result: every trigger fires N times (once per agent sharing the workspace), every scheduled time runs N agents in parallel, every task.pending poll fans out N ways. There is currently no way to declare which agent in a shared workspace should "own" the Cue config.

Concrete repro from my setup

I have an Obsidian vault registered as two agents (different model/profile, same workspace):

Obsidian          claude-code  $HOME/.../V1   id 160dff0f-...
Obsidian(Sonnet)  claude-code  $HOME/.../V1   id fe7c6b37-...

$HOME/.../V1/.maestro/cue.yaml contains a time.scheduled subscription at 18:00 and a task.pending subscription on research.md. As soon as the engine registers both agents, both fire every subscription — the 18:00 summary runs twice, the research-task pipeline kicks off two parallel investigations clobbering each other's outputs in the same Research/<date>-<slug>/ folder.

This is a legitimate (and increasingly common) workflow: keep one workspace, switch between Opus and Sonnet agents against it depending on the task. Today, doing so multiplies the cost and chaos of every Cue trigger.

Why it's a scheduler concern, not a YAML-author concern

A subscription already supports agent_id for fan-out targeting, but that doesn't help here — there's no way to say "only the agent with id X should ever evaluate this whole config". A YAML author who wants single-fire semantics today has to:

  • duplicate the config per agent and gate each one with agent_id filters, OR
  • pick one agent in the UI and remember never to use the other one for unattended work

Both are footguns. The engine knows which agents share a project root; it should be the one to dedupe.

Proposed fix

Add an optional owner_agent_id (or similarly named) field to the top-level settings: block of cue.yaml:

settings:
  owner_agent_id: 160dff0f-db39-4245-9756-39662cd75499  # Obsidian — Opus
  timeout_minutes: 30
  

subscriptions:
  - name: "research queue"
    event: task.pending
    watch: "research.md"
    prompt_file: .maestro/prompts/cue-research.md

Behavior:

  • If owner_agent_id is set, only the agent whose id matches loads/runs the subscriptions in this file. All other agents whose projectRoot equals this project see the config, log a one-line [CUE] "Obsidian(Sonnet)" skipping cue.yaml — owner_agent_id targets "Obsidian", and register no triggers.
  • If owner_agent_id is absent, fall back to a sensible default — see "Default policy" below.
  • Per-subscription agent_id continues to work for fan-out within the owner.

Default policy when owner_agent_id is unset

This is the trickier half. Two reasonable options:

  1. First-registered wins — the first agent to call initSession for a given projectRoot "claims" the config; subsequent agents on the same root skip with a warning. Deterministic on a sorted session list, easy to reason about, but order-dependent if the user reshuffles agents.
  2. Warn loud, run anyway — preserve today's behavior, but on detection of multiple agents sharing a project root with cue.yaml, surface a prominent banner in the Cue modal: "2 agents share /path/to/V1 — every trigger will fire twice. Set settings.owner_agent_id to disambiguate."

I'd argue for (1) plus the banner from (2) — it's safer and the banner explains how to make it deterministic.

Suggested fix bundle

  1. Add owner_agent_id?: string to the settings schema.
  2. In cue-session-runtime-service.ts's initSession, after loadCueConfigDetailed returns ok, check if config.settings.owner_agent_id is present and != session.id — if so, log + return early.
  3. If owner_agent_id is unset, group sessions by projectRoot, pick the first by stable order, and treat it as implicit owner. Log the implicit choice so users can see what claimed the config.
  4. Surface a banner in the Cue modal when multiple sessions share a project root, regardless of whether owner_agent_id is set.
  5. Docs: add a "Sharing a workspace across agents" section to maestro-cue-configuration.md.

Related

(Found together while wiring up a research pipeline against an Obsidian vault that I happened to have registered as two agents.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions