flower
/
All briefs
complete note flower

/roster: one-click spawn & monitor flower daemons (Solo bridge, v2)

canonical · plan

Spec

markdown

hand-off · dispatch

Dispatch

Auto-dispatch

when it reaches planned

Design-loop

design pass before build

This brief is complete — dispatch is closed.

#12 done fresh flower · flower/roster-spawn-ui
2 scratchpads
You are being dispatched from flower Brief #22: /roster: one-click spawn & monitor flower daemons (Solo bridge, v2)

Recall pointer:
- Use recall_brief with id 22 for the full folder if you need provenance.

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/roster-spawn-ui
- worktree: not specified
- kind: fresh

Current brief spec:
## Goal
Surface daemon spawning + monitoring in the flower `/roster` UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **v2 = one-click.**

## What's now in place (unblocked as of 2026-07-01)
- **The seam exists (Brief #26, merged):** `daemon_agents` has an `expected` status +
  `daemon_register_expected` MCP tool; `daemon_checkin` reconciles an expected (role,project)
  placeholder → live (no phantom rows); `/roster` can render a daemon as "spawning". Roster health
  degrades gracefully when only session-link data exists.
- **The spawn packet render exists (spawn-flow-ui, 973):** `/roster` already renders a filled
  charter + Solo spawn instructions from `SpawnPacketService`.
- **The Solo-bridge answer = `solo-cli`** (the non-MCP Solo bridge). flower does NOT hold the Solo
  MCP, but it CAN shell out to `solo-cli` to spawn an agent + send the kickoff.

## Scope (split)
**Backend bridge (this dispatch):**
1. Design the Solo-bridge spawn flow via `solo-cli`: given (project, role, optional charter
   override), (a) `daemon_register_expected` to show "spawning" on the roster, (b) invoke solo-cli
   to `spawn_agent` in the target Solo project, (c) deliver the rendered charter packet as the
   kickoff, (d) the daemon's own `daemon_checkin` then reconciles the expected row → live.
2. **SAFETY GATE — do NOT wire a live agent-spawn to a button without operator review.** Spawning
   agents is a real, sensitive action. First **report the bridge design + safety model via
   brief_append** (auth, how the target Solo project is resolved, guardrails: confirm before
   spawning into a project with active operator sessions, default new daemons to HOLD/no-loop-timer).
   Build + unit-test the plumbing (register-expected, packet handoff, solo-cli invocation behind a
   small service seam that can be faked in tests), but keep the actual live spawn behind the gate /
   an explicit confirm until the design is reviewed.

**UI (follow-up dispatch to design 973 after #25):** `/roster` "Spawn daemon" action (project+role+
charter preview) calling the backend bridge; monitor rows (expected/live/stale/dead, context,
needs_compaction, last checkin) + actions (poke / request-compaction / retire).

## Open questions to resolve in the design report
- How does flower authenticate to / target the right Solo project headlessly via solo-cli?
- "Go live" == arming the daemon's recurring loop timer — owned by flower or the daemon itself?

## Acceptance (backend slice)
- Bridge service + `daemon_register_expected` integration, unit-tested with a faked solo-cli seam.
- Design + safety model reported via `brief_append`; live-spawn gated pending review.
- `php artisan test` green + pint. `Brief: #22` trailer; brief_append; brief_dispatch_complete if available.

## Provenance
2026-07-01 daemon-spawn dogfood + operator ask. Prereq (Brief #26 seam) merged; v1 copy-paste skipped.

Recent/key trace events:
[6] link_added flower-orchestrator: (no body)
[7] spec_snapshot flower-orchestrator: ## Goal
Surface daemon spawning + monitoring in the flower /roster UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **Skip the
copy-paste v1; build the one-click v2** (operator decision, 2026-07-01).

## Background — the mechanism already exists server-side
- `SpawnPacketService` renders the full spawn packet: the filled role charter (via
  `recall_charters`) + step-by-step spawn/readiness/`daemon_checkin`/handoff instructions.
  Charters are `PromptTemplate` rows (kind=daemon_charter), editable in the prompt-library UI.
- `daemon_checkin` self-registers a daemon into the roster. Freshly-spawned agents negotiate
  the FULL flower MCP surface — verified 2026-07-01: orchestrator + refine daemons spawned
  into thedarkroom_automation registered cleanly as daemon ids 6/7.
- Today flower deliberately does NOT hold the Solo MCP (the packet says "flower is only
  rendering this packet; it does not hold Solo").

## v2 scope — one-click spawn via a Solo bridge
- /roster gains a "Spawn daemon" action: choose project + role (+ optional charter override /
  draft-body preview via `SpawnPacketService::previewCharter`).
- flower holds a **Solo bridge** (solo-cli or a Solo MCP handle) that can actually
  `spawn_agent` in the target Solo project, deliver the kickoff (charter packet), confirm
  readiness, then the daemon self-checks-in and appears live in the roster.
- Monitor: roster rows already derive live/idle/stale/dead; add context size, needs_compaction,
  last checkin, and actions (poke / request-compaction / retire).
- Guardrails: confirm before spawning into a project with active operator sessions; default
  new daemons to a HOLD posture (no autonomous loop timer) until explicitly enabled.

## Open questions
- Where does the Solo bridge live and how does flower authenticate to Solo MCP headlessly?
- "Go live" == arming the recurring loop timer — owned by flower or by the daemon itself?

## Provenance
2026-07-01 TDA daemon-spawn dogfood + operator request: "a way to fire those orchestrators up
in those projects properly prompted/instructed on their roles" + a /roster start/monitor surface.
[8] refinement flower-orchestrator: ## Goal
Surface daemon spawning + monitoring in the flower `/roster` UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **v2 = one-click.**

## What's now in place (unblocked as of 2026-07-01)
- **The seam exists (Brief #26, merged):** `daemon_agents` has an `expected` status +
  `daemon_register_expected` MCP tool; `daemon_checkin` reconciles an expected (role,project)
  placeholder → live (no phantom rows); `/roster` can render a daemon as "spawning". Roster health
  degrades gracefully when only session-link data exists.
- **The spawn packet render exists (spawn-flow-ui, 973):** `/roster` already renders a filled
  charter + Solo spawn instructions from `SpawnPacketService`.
- **The Solo-bridge answer = `solo-cli`** (the non-MCP Solo bridge). flower does NOT hold the Solo
  MCP, but it CAN shell out to `solo-cli` to spawn an agent + send the kickoff.

## Scope (split)
**Backend bridge (this dispatch):**
1. Design the Solo-bridge spawn flow via `solo-cli`: given (project, role, optional charter
   override), (a) `daemon_register_expected` to show "spawning" on the roster, (b) invoke solo-cli
   to `spawn_agent` in the target Solo project, (c) deliver the rendered charter packet as the
   kickoff, (d) the daemon's own `daemon_checkin` then reconciles the expected row → live.
2. **SAFETY GATE — do NOT wire a live agent-spawn to a button without operator review.** Spawning
   agents is a real, sensitive action. First **report the bridge design + safety model via
   brief_append** (auth, how the target Solo project is resolved, guardrails: confirm before
   spawning into a project with active operator sessions, default new daemons to HOLD/no-loop-timer).
   Build + unit-test the plumbing (register-expected, packet handoff, solo-cli invocation behind a
   small service seam that can be faked in tests), but keep the actual live spawn behind the gate /
   an explicit confirm until the design is reviewed.

**UI (follow-up dispatch to design 973 after #25):** `/roster` "Spawn daemon" action (project+role+
charter preview) calling the backend bridge; monitor rows (expected/live/stale/dead, context,
needs_compaction, last checkin) + actions (poke / request-compaction / retire).

## Open questions to resolve in the design report
- How does flower authenticate to / target the right Solo project headlessly via solo-cli?
- "Go live" == arming the daemon's recurring loop timer — owned by flower or the daemon itself?

## Acceptance (backend slice)
- Bridge service + `daemon_register_expected` integration, unit-tested with a faked solo-cli seam.
- Design + safety model reported via `brief_append`; live-spawn gated pending review.
- `php artisan test` green + pint. `Brief: #22` trailer; brief_append; brief_dispatch_complete if available.

## Provenance
2026-07-01 daemon-spawn dogfood + operator ask. Prereq (Brief #26 seam) merged; v1 copy-paste skipped.
[9] status_change flower-orchestrator: (no body)
[10] dispatched flower-orchestrator: Dispatch request #7 queued for flower.
[11] participant_joined flower-backend-977: (no body)
[12] note_added flower-backend-977: Bridge design + safety model (backend worker 977, before implementation):

- Target resolution/auth: flower shells out to configured solo-cli (`config("flower.solo.binary")`, optional `flower.solo.app_data_dir`) and accepts JSON only. The bridge resolves the Flower project, lists Solo projects, and requires exactly one Solo project with canonical path matching the Flower project root_path. Missing or ambiguous mappings fail closed before registering expected or spawning.
- Spawn sequence: render packet with `SpawnPacketService`, register expected with `DaemonRosterService::registerExpected`, spawn through a fakeable Solo client seam, send the packet as kickoff, then wait for the daemon to reconcile itself via `daemon_checkin`. Flower will not synthesize live status after spawn.
- Safety gate: live spawn requires explicit `confirmed=true`; dry run/plan is the default. No live spawn is wired to a roster button in this backend slice.
- Active operator guard: before confirmed spawn, inspect running Solo processes for the target Solo project and block if active operator/manual sessions are present. This implementation reports a blocker; it does not override automatically.
- HOLD/no-loop posture: kickoff tells the daemon to start in HOLD, run whoami + daemon_checkin, and not arm any recurring Solo loop timer until the operator enables it. Recurring loop ownership stays with daemon/operator review, not automatic backend spawn.
- Tests will fake Solo client behavior and assert project resolution, expected registration, packet delivery, confirmation gating, active-session blocking, and no live-status fabrication.
[13] note_added flower-backend-977: Completed backend Solo-bridge slice on branch `flower/roster-spawn-bridge`.

- Commit: `27843fa916c9f1074f96b2eb66fb201fd221a43d` (`Add daemon Solo spawn bridge`, trailer `Brief: #22`).
- Added `SpawnDaemonBridge` with non-mutating plan, explicit confirmed live spawn, path-based Solo project resolution through `solo-cli projects list`, active operator/manual process blocking through project-scoped `solo-cli processes list`, expected-daemon registration before fakeable Solo spawn, and HOLD/no-loop packet delivery.
- Extended `SoloClient` with fakeable `agents`, project-scoped `runningProcesses`, and `spawnAgent` primitives; extended `SpawnPacketService` with charter body override + HOLD packet mode.
- No route, Livewire action, or MCP live-spawn tool was wired. Live spawn remains service-gated by explicit confirmation and safety checks.
- Verification: `~/bin/php artisan test` passed (385 tests, 384 passed, 1 skipped, 2802 assertions). Pint passed on touched files.
[14] dispatched flower-backend-977: Dispatch request #7 marked done.
[15] status_change flower-backend-977: (no body)
[16] status_change flower-orchestrator: (no body)
[17] note_added flower-orchestrator: [orchestrator 969, 2026-07-01] Backend Solo-bridge slice DONE + merged (master f17d2c4, commit 27843fa): SpawnDaemonBridge (plan/confirmed-spawn), SoloClient project-scoped lookup + spawnAgent, config/flower.php solo bridge settings (block_active_operator_sessions default true), DaemonSpawnSafetyException, tests. **Live spawn is GATED — no UI/route/MCP tool wired.** Design + safety model = event 188 (review before enabling live spawn).

RE-OPENED to in_progress: the dispatch-completion rollup auto-marked the brief `complete` when the backend dispatch closed, but #22's scope still has: (1) the /roster "Spawn daemon" + monitor UI (design lane, after #25), (2) enabling the live spawn after operator review of the design report. Remaining scope tracked here.

NB (hygiene nuance for the rollup): a multi-slice brief (backend + UI) shouldn't read `complete` after just one slice's dispatch closes. Options to consider: worker should set in_progress (not complete) when more scope remains, OR each slice is its own brief. Candidate follow-up.

Recommended linked context:
{
    "todos": [],
    "scratchpads": [
        {
            "id": 346,
            "solo_scratchpad_id": "1026",
            "name": "Orchestrator HANDOFF — flower build (live state)",
            "archived": false,
            "revision": 17
        },
        {
            "id": 351,
            "solo_scratchpad_id": "1031",
            "name": "Spawn packets / charters / dispatch conventions — working notes",
            "archived": false,
            "revision": 1
        }
    ]
}

Execution notes:
- Treat the brief as the source of truth.
- Keep work scoped to this dispatch request.
- Use brief_append / brief_update_status when reporting material progress.
- Add a git commit trailer `Brief: #22` to every commit for this brief so flower can exact-link commits back to the brief.
#7 done fresh flower · flower/roster-spawn-bridge
2 scratchpads
You are being dispatched from flower Brief #22: /roster: one-click spawn & monitor flower daemons (Solo bridge, v2)

Recall pointer:
- Use recall_brief with id 22 for the full folder if you need provenance.

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/roster-spawn-bridge
- worktree: not specified
- kind: fresh

Current brief spec:
## Goal
Surface daemon spawning + monitoring in the flower `/roster` UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **v2 = one-click.**

## What's now in place (unblocked as of 2026-07-01)
- **The seam exists (Brief #26, merged):** `daemon_agents` has an `expected` status +
  `daemon_register_expected` MCP tool; `daemon_checkin` reconciles an expected (role,project)
  placeholder → live (no phantom rows); `/roster` can render a daemon as "spawning". Roster health
  degrades gracefully when only session-link data exists.
- **The spawn packet render exists (spawn-flow-ui, 973):** `/roster` already renders a filled
  charter + Solo spawn instructions from `SpawnPacketService`.
- **The Solo-bridge answer = `solo-cli`** (the non-MCP Solo bridge). flower does NOT hold the Solo
  MCP, but it CAN shell out to `solo-cli` to spawn an agent + send the kickoff.

## Scope (split)
**Backend bridge (this dispatch):**
1. Design the Solo-bridge spawn flow via `solo-cli`: given (project, role, optional charter
   override), (a) `daemon_register_expected` to show "spawning" on the roster, (b) invoke solo-cli
   to `spawn_agent` in the target Solo project, (c) deliver the rendered charter packet as the
   kickoff, (d) the daemon's own `daemon_checkin` then reconciles the expected row → live.
2. **SAFETY GATE — do NOT wire a live agent-spawn to a button without operator review.** Spawning
   agents is a real, sensitive action. First **report the bridge design + safety model via
   brief_append** (auth, how the target Solo project is resolved, guardrails: confirm before
   spawning into a project with active operator sessions, default new daemons to HOLD/no-loop-timer).
   Build + unit-test the plumbing (register-expected, packet handoff, solo-cli invocation behind a
   small service seam that can be faked in tests), but keep the actual live spawn behind the gate /
   an explicit confirm until the design is reviewed.

**UI (follow-up dispatch to design 973 after #25):** `/roster` "Spawn daemon" action (project+role+
charter preview) calling the backend bridge; monitor rows (expected/live/stale/dead, context,
needs_compaction, last checkin) + actions (poke / request-compaction / retire).

## Open questions to resolve in the design report
- How does flower authenticate to / target the right Solo project headlessly via solo-cli?
- "Go live" == arming the daemon's recurring loop timer — owned by flower or the daemon itself?

## Acceptance (backend slice)
- Bridge service + `daemon_register_expected` integration, unit-tested with a faked solo-cli seam.
- Design + safety model reported via `brief_append`; live-spawn gated pending review.
- `php artisan test` green + pint. `Brief: #22` trailer; brief_append; brief_dispatch_complete if available.

## Provenance
2026-07-01 daemon-spawn dogfood + operator ask. Prereq (Brief #26 seam) merged; v1 copy-paste skipped.

Recent/key trace events:
[1] participant_joined flower-orchestrator: (no body)
[2] note_added flower-orchestrator: Operator asked for a /roster surface to start + monitor orchestrator/ops/refine daemons in any project. Skip v1 copy-paste; build v2 one-click Solo bridge.
[3] plan_proposed flower-orchestrator: ## Goal
Surface daemon spawning + monitoring in the flower /roster UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **Skip the
copy-paste v1; build the one-click v2** (operator decision, 2026-07-01).

## Background — the mechanism already exists server-side
- `SpawnPacketService` renders the full spawn packet: the filled role charter (via
  `recall_charters`) + step-by-step spawn/readiness/`daemon_checkin`/handoff instructions.
  Charters are `PromptTemplate` rows (kind=daemon_charter), editable in the prompt-library UI.
- `daemon_checkin` self-registers a daemon into the roster. Freshly-spawned agents negotiate
  the FULL flower MCP surface — verified 2026-07-01: orchestrator + refine daemons spawned
  into thedarkroom_automation registered cleanly as daemon ids 6/7.
- Today flower deliberately does NOT hold the Solo MCP (the packet says "flower is only
  rendering this packet; it does not hold Solo").

## v2 scope — one-click spawn via a Solo bridge
- /roster gains a "Spawn daemon" action: choose project + role (+ optional charter override /
  draft-body preview via `SpawnPacketService::previewCharter`).
- flower holds a **Solo bridge** (solo-cli or a Solo MCP handle) that can actually
  `spawn_agent` in the target Solo project, deliver the kickoff (charter packet), confirm
  readiness, then the daemon self-checks-in and appears live in the roster.
- Monitor: roster rows already derive live/idle/stale/dead; add context size, needs_compaction,
  last checkin, and actions (poke / request-compaction / retire).
- Guardrails: confirm before spawning into a project with active operator sessions; default
  new daemons to a HOLD posture (no autonomous loop timer) until explicitly enabled.

## Open questions
- Where does the Solo bridge live and how does flower authenticate to Solo MCP headlessly?
- "Go live" == arming the recurring loop timer — owned by flower or by the daemon itself?

## Provenance
2026-07-01 TDA daemon-spawn dogfood + operator request: "a way to fire those orchestrators up
in those projects properly prompted/instructed on their roles" + a /roster start/monitor surface.
[4] status_change flower-orchestrator: (no body)
[5] link_added flower-orchestrator: (no body)
[6] link_added flower-orchestrator: (no body)
[7] spec_snapshot flower-orchestrator: ## Goal
Surface daemon spawning + monitoring in the flower /roster UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **Skip the
copy-paste v1; build the one-click v2** (operator decision, 2026-07-01).

## Background — the mechanism already exists server-side
- `SpawnPacketService` renders the full spawn packet: the filled role charter (via
  `recall_charters`) + step-by-step spawn/readiness/`daemon_checkin`/handoff instructions.
  Charters are `PromptTemplate` rows (kind=daemon_charter), editable in the prompt-library UI.
- `daemon_checkin` self-registers a daemon into the roster. Freshly-spawned agents negotiate
  the FULL flower MCP surface — verified 2026-07-01: orchestrator + refine daemons spawned
  into thedarkroom_automation registered cleanly as daemon ids 6/7.
- Today flower deliberately does NOT hold the Solo MCP (the packet says "flower is only
  rendering this packet; it does not hold Solo").

## v2 scope — one-click spawn via a Solo bridge
- /roster gains a "Spawn daemon" action: choose project + role (+ optional charter override /
  draft-body preview via `SpawnPacketService::previewCharter`).
- flower holds a **Solo bridge** (solo-cli or a Solo MCP handle) that can actually
  `spawn_agent` in the target Solo project, deliver the kickoff (charter packet), confirm
  readiness, then the daemon self-checks-in and appears live in the roster.
- Monitor: roster rows already derive live/idle/stale/dead; add context size, needs_compaction,
  last checkin, and actions (poke / request-compaction / retire).
- Guardrails: confirm before spawning into a project with active operator sessions; default
  new daemons to a HOLD posture (no autonomous loop timer) until explicitly enabled.

## Open questions
- Where does the Solo bridge live and how does flower authenticate to Solo MCP headlessly?
- "Go live" == arming the recurring loop timer — owned by flower or by the daemon itself?

## Provenance
2026-07-01 TDA daemon-spawn dogfood + operator request: "a way to fire those orchestrators up
in those projects properly prompted/instructed on their roles" + a /roster start/monitor surface.
[8] refinement flower-orchestrator: ## Goal
Surface daemon spawning + monitoring in the flower `/roster` UI so the operator can start
orchestrator/ops/refine daemons in any project without hand-driving Solo. **v2 = one-click.**

## What's now in place (unblocked as of 2026-07-01)
- **The seam exists (Brief #26, merged):** `daemon_agents` has an `expected` status +
  `daemon_register_expected` MCP tool; `daemon_checkin` reconciles an expected (role,project)
  placeholder → live (no phantom rows); `/roster` can render a daemon as "spawning". Roster health
  degrades gracefully when only session-link data exists.
- **The spawn packet render exists (spawn-flow-ui, 973):** `/roster` already renders a filled
  charter + Solo spawn instructions from `SpawnPacketService`.
- **The Solo-bridge answer = `solo-cli`** (the non-MCP Solo bridge). flower does NOT hold the Solo
  MCP, but it CAN shell out to `solo-cli` to spawn an agent + send the kickoff.

## Scope (split)
**Backend bridge (this dispatch):**
1. Design the Solo-bridge spawn flow via `solo-cli`: given (project, role, optional charter
   override), (a) `daemon_register_expected` to show "spawning" on the roster, (b) invoke solo-cli
   to `spawn_agent` in the target Solo project, (c) deliver the rendered charter packet as the
   kickoff, (d) the daemon's own `daemon_checkin` then reconciles the expected row → live.
2. **SAFETY GATE — do NOT wire a live agent-spawn to a button without operator review.** Spawning
   agents is a real, sensitive action. First **report the bridge design + safety model via
   brief_append** (auth, how the target Solo project is resolved, guardrails: confirm before
   spawning into a project with active operator sessions, default new daemons to HOLD/no-loop-timer).
   Build + unit-test the plumbing (register-expected, packet handoff, solo-cli invocation behind a
   small service seam that can be faked in tests), but keep the actual live spawn behind the gate /
   an explicit confirm until the design is reviewed.

**UI (follow-up dispatch to design 973 after #25):** `/roster` "Spawn daemon" action (project+role+
charter preview) calling the backend bridge; monitor rows (expected/live/stale/dead, context,
needs_compaction, last checkin) + actions (poke / request-compaction / retire).

## Open questions to resolve in the design report
- How does flower authenticate to / target the right Solo project headlessly via solo-cli?
- "Go live" == arming the daemon's recurring loop timer — owned by flower or the daemon itself?

## Acceptance (backend slice)
- Bridge service + `daemon_register_expected` integration, unit-tested with a faked solo-cli seam.
- Design + safety model reported via `brief_append`; live-spawn gated pending review.
- `php artisan test` green + pint. `Brief: #22` trailer; brief_append; brief_dispatch_complete if available.

## Provenance
2026-07-01 daemon-spawn dogfood + operator ask. Prereq (Brief #26 seam) merged; v1 copy-paste skipped.

Recommended linked context:
{
    "todos": [],
    "scratchpads": [
        {
            "id": 346,
            "solo_scratchpad_id": "1026",
            "name": "Orchestrator HANDOFF — flower build (live state)",
            "archived": false,
            "revision": 17
        },
        {
            "id": 351,
            "solo_scratchpad_id": "1031",
            "name": "Spawn packets / charters / dispatch conventions — working notes",
            "archived": false,
            "revision": 1
        }
    ]
}

Execution notes:
- Treat the brief as the source of truth.
- Keep work scoped to this dispatch request.
- Use brief_append / brief_update_status when reporting material progress.
- Add a git commit trailer `Brief: #22` to every commit for this brief so flower can exact-link commits back to the brief.

provenance · append-only

Trace

live
or paste a screenshot uploading…
  1. link added 4d ago
    agent · system:commit-trailer
  2. status change 4d ago
    agent · flower-orchestrator
  3. note added 4d ago

    Remaining #22 scope DONE (branch flower/spawn-live-selector off master f32d2ed) — full suite green (462 passed, 1 pre-existing skip, 3264 assertions), pint clean. NOT merged — handing back for review/merge. One commit `7053e12` (Brief: #22 trailer). ## What shipped **(1) Harness selector — was broken, now fixed.** #34 populated $agentTools/$spawnAgentToolId but the composer blade never rendered a control, so the operator couldn't pick a harness. Added the harness <select> (bound to spawnAgentToolId, populated from the live solo-cli agent tools), plus updatedSpawnAgentToolId() → SoloAgentToolService::rememberSelection to persist last-chosen per actor+project (planning already persisted via resolveForSpawn remember:true; this makes it stick on select too). Falls back to "no harnesses available" when solo-cli is unreachable. **(2) Live spawn — turned ON.** Added confirmSpawn() → SpawnDaemonBridge::spawn(confirmed:true, agentToolId:selected). The plan partial now shows a "Spawn daemon (live)" button (native wire:confirm dialog) whenever the pre-flight is clear. Every backend guard is intact: explicit confirmation, safety.blocked ⇒ refuse, block_active_operator_sessions (KEPT, default true), name-collision, HOLD/no-loop posture. A blocked confirm re-runs the pre-flight so the operator sees why; a success banner points at the roster. **(3) Click-to-copy packet fallback KEPT** — a "Copy packet" button on the plan (copies plan.packet) so a manual Solo spawn is always available. Tests: inverted the old "no live spawn action" guard test into coverage that confirmSpawn spawns through the bridge (asserts one solo.spawnAgent call w/ selected harness + derived name flower-ops + expected daemon row), stays gated by the active-operator guard (terminal/manual process → blocked, zero spawn calls, zero rows), and that the selector lists/defaults/persists a harness. All via the FakeRosterSoloClient seam. Note on event-266 items: the double-prefix ("flower-flower-refine") + name-collision are already resolved by #34's DaemonNaming (agent name = flower-ops) + the bridge's collision check — the plan/spawn use the correct name. The heartbeat-cadence (item 2) and polling-cadence concrete values (item 3) are NOT in this dispatch's scope and remain open. ## ⚠️ Live-spawn safety — please confirm before it goes live on flower.test 1. **This actually spawns a real agent** (solo-cli processes spawn) on operator confirm. Guards remain as above. Confirm you're OK enabling it in the served MAIN env. 2. **Active-operator guard nuance:** flower-* named standing daemons are intentionally NOT treated as blocking operator sessions (so a running flower-orchestrator won't block spawning a flower-refine). Under the OLD logic your event-266 pre-flight flagged flower-ops/flower-orchestrator red; under current logic they won't block — only genuine terminal/manual/operator-owned processes do. Confirm that's the desired semantics. 3. **HOLD posture:** the daemon checks in but does NOT arm a recurring loop timer — "going live" (arming the loop) stays a separate manual step. Confirm. 4. **Failure visibility:** flower registers the expected row, calls spawn, then trusts daemon_checkin (no fabricated live status). A silently-failed spawn will linger as a "spawning" row until it goes stale/dead — by design, but worth knowing. 5. **Browser verification is pending merge** (worktree isn't served; flower.test = MAIN on master). Recommend after merge: load /roster, open the composer, confirm the harness dropdown lists real tools, run ONE dry-run plan, then a single real live spawn into a safe project to validate end-to-end.

    agent · flower-other
  4. note added 4d ago

    solo-cli connectivity blocker (that gated LIVE spawn) is RESOLVED — see brief #34 for full evidence. Summary: live Solo API reachable (curl /api/version → 200), `solo-cli --json agents list` returns real tools (Claude=3, Codex=4). Earlier `stale_discovery` was a transient Solo-restart blip; no SOLO_APP_DATA_DIR needed (default ~/.config/soloterm is correct; SoloClient only passes --app-data-dir when non-empty). => remaining gates for #22 live-spawn are now just: (1) operator review of the safety design (event 188) and (2) the per-spawn harness selector (built in #34 backend + #22 UI follow-up). Connectivity is no longer a blocker.

    agent · flower-orchestrator
  5. link added 4d ago
    agent · system:commit-trailer
  6. link added 4d ago
    agent · system:commit-trailer
  7. note added 4d ago

    Some follow up notes after reviewing the UI side of the /roster spawning of agents: 1) I clicked the button to bring up the "Spawn a daemon" form and selected 'flower' as the project and 'refine' as the type and then hit preview charter and the first line says this: `You are flower-flower-refine (role: refine) for project 16 (flower).` Two things, first - did we double up on the prefix on purpose? second - are we ensuring we don't already have agents with these names in solo before spawning/naming? 2) The charter includes this: "Heartbeat with daemon_checkin(role:refine, project:flower) when due" - but it never indicates when "due" is. We should make a flower configuration key/value to hold what this value is, <= 30 minutes or if it's timer is > 30 minutes, on each timer/ping/wake? And with this we could then actually determine if a daemon on the roster is MIA based on no recent pings within the expected timeframe. (We do need to ensure that our 'expected timeframe' is somehow configured so that the daemon being on a long poll doesn't continually get it marked as missing) 3) Same thing with the polling Cadence - it says "quickly", "slower", "slowest" - we need to define these in concrete values so there's nothing left to interpretation. And also so that we can have something to fall back on definitely to know if we _should_ have had something done by now given that we should know/expect action from a daemon every $fast_polling_cadence or whatever. 4) I clicked the "Plan spawn (dry run)" button and it showed me the pre-flight report and it indicated that "Operator sessions" was red and said this: "2 active: flower-ops, flower-orchestrator". It also indicate that "Agent tool" was red: "SOLO_AGENT_TOOL_ID is not configured."

    operator · operator:mike
  8. participant joined 4d ago
    system · operator:mike
  9. status change 4d ago
    agent · flower-orchestrator
  10. status change 4d ago
    agent · flower-orchestrator
  11. dispatched 4d ago

    Dispatch request #12 marked done.

    agent · flower-orchestrator
  12. note added 4d ago

    ## UI slice DONE — dispatch #12 (branch `flower/roster-spawn-ui`, off master 833b7ed) Built the /roster UI on top of the merged backend bridge. Two per-unit commits, each `Brief: #22`: **Unit 1 — Spawn daemon composer (commit 1537e7e).** A "Spawn daemon" toggle in the /roster heading opens a composer: pick project + role, optional charter override, then **Preview charter** (`SpawnPacketService::previewCharter`) or **Plan spawn (dry run)** (`SpawnDaemonBridge::plan`). The plan renders a safety **pre-flight** — destination Solo project, agent tool id, agent name, HOLD posture, active-operator-session guard, confirmation gate — plus the exact packet a real spawn would deliver, and a would-block / pre-flight-clear verdict. **No live spawn is wired**: the composer only ever calls the non-mutating plan/preview paths, never `spawn()`. A test asserts the component exposes no spawn action and that planning creates zero daemon rows / zero Solo calls. Live spawn stays gated pending your review of the event-188 design. **Unit 2 — Row actions (commit 3dae39b).** Each daemon row gains poke · request-compaction · retire. **request-compaction is wired** to `DaemonRosterService::requestCompaction` (non-destructive; row re-renders with the "compaction · requested" badge). **poke + retire are disabled stubs** (no backing service yet) with tooltips. Also fixed a latent render bug this exposed: the compaction badge echoed the `DaemonCompactionState` enum directly, which would TypeError once a real value was set — normalized to the enum value. Monitor fields (expected/live/stale/dead, context_size, needs_compaction, last check-in) were already present and verified. Green: `php artisan test` 401 passed / 1 pre-existing skip (+7 new roster tests); `pint` clean; `npm run build` compiles. Left live verification on flower.test to the orchestrator (worktree isn't served). **Remaining #22 scope (yours):** enabling the live confirmed spawn after operator review of the event-188 safety model — deliberately not wired here. **NB:** the dispatch instructions asked me to call `brief_dispatch_complete` when done, but that tool is NOT in this design-lane MCP surface (only brief_dispatch / brief_claim / brief_update_status are). So dispatch #12 can't be marked done from here — flagging for orchestrator closure. Filed as mcp_issue feedback too. Leaving brief status untouched (multi-slice; you own the rollup). Stopping for review/merge.

    agent · flower-other
  13. participant joined 4d ago
    system · flower-other
  14. link added 4d ago
    agent · system:commit-trailer
  15. participant joined 4d ago
    system · system:commit-trailer
  16. dispatched 4d ago

    Dispatch request #12 queued for flower.

    agent · flower-orchestrator
  17. status change 4d ago
    agent · flower-orchestrator
  18. note added 4d ago

    [orchestrator 969, 2026-07-01] Backend Solo-bridge slice DONE + merged (master f17d2c4, commit 27843fa): SpawnDaemonBridge (plan/confirmed-spawn), SoloClient project-scoped lookup + spawnAgent, config/flower.php solo bridge settings (block_active_operator_sessions default true), DaemonSpawnSafetyException, tests. **Live spawn is GATED — no UI/route/MCP tool wired.** Design + safety model = event 188 (review before enabling live spawn). RE-OPENED to in_progress: the dispatch-completion rollup auto-marked the brief `complete` when the backend dispatch closed, but #22's scope still has: (1) the /roster "Spawn daemon" + monitor UI (design lane, after #25), (2) enabling the live spawn after operator review of the design report. Remaining scope tracked here. NB (hygiene nuance for the rollup): a multi-slice brief (backend + UI) shouldn't read `complete` after just one slice's dispatch closes. Options to consider: worker should set in_progress (not complete) when more scope remains, OR each slice is its own brief. Candidate follow-up.

    agent · flower-orchestrator
  19. status change 4d ago
    agent · flower-orchestrator
  20. status change 4d ago
    agent · flower-backend-977
  21. dispatched 4d ago

    Dispatch request #7 marked done.

    agent · flower-backend-977
  22. note added 4d ago

    Completed backend Solo-bridge slice on branch `flower/roster-spawn-bridge`. - Commit: `27843fa916c9f1074f96b2eb66fb201fd221a43d` (`Add daemon Solo spawn bridge`, trailer `Brief: #22`). - Added `SpawnDaemonBridge` with non-mutating plan, explicit confirmed live spawn, path-based Solo project resolution through `solo-cli projects list`, active operator/manual process blocking through project-scoped `solo-cli processes list`, expected-daemon registration before fakeable Solo spawn, and HOLD/no-loop packet delivery. - Extended `SoloClient` with fakeable `agents`, project-scoped `runningProcesses`, and `spawnAgent` primitives; extended `SpawnPacketService` with charter body override + HOLD packet mode. - No route, Livewire action, or MCP live-spawn tool was wired. Live spawn remains service-gated by explicit confirmation and safety checks. - Verification: `~/bin/php artisan test` passed (385 tests, 384 passed, 1 skipped, 2802 assertions). Pint passed on touched files.

    agent · flower-backend-977
  23. note added 4d ago

    Bridge design + safety model (backend worker 977, before implementation): - Target resolution/auth: flower shells out to configured solo-cli (`config("flower.solo.binary")`, optional `flower.solo.app_data_dir`) and accepts JSON only. The bridge resolves the Flower project, lists Solo projects, and requires exactly one Solo project with canonical path matching the Flower project root_path. Missing or ambiguous mappings fail closed before registering expected or spawning. - Spawn sequence: render packet with `SpawnPacketService`, register expected with `DaemonRosterService::registerExpected`, spawn through a fakeable Solo client seam, send the packet as kickoff, then wait for the daemon to reconcile itself via `daemon_checkin`. Flower will not synthesize live status after spawn. - Safety gate: live spawn requires explicit `confirmed=true`; dry run/plan is the default. No live spawn is wired to a roster button in this backend slice. - Active operator guard: before confirmed spawn, inspect running Solo processes for the target Solo project and block if active operator/manual sessions are present. This implementation reports a blocker; it does not override automatically. - HOLD/no-loop posture: kickoff tells the daemon to start in HOLD, run whoami + daemon_checkin, and not arm any recurring Solo loop timer until the operator enables it. Recurring loop ownership stays with daemon/operator review, not automatic backend spawn. - Tests will fake Solo client behavior and assert project resolution, expected registration, packet delivery, confirmation gating, active-session blocking, and no live-status fabrication.

    agent · flower-backend-977
  24. participant joined 4d ago
    system · flower-backend-977
  25. dispatched 4d ago

    Dispatch request #7 queued for flower.

    agent · flower-orchestrator
  26. status change 4d ago
    agent · flower-orchestrator
  27. refinement 4d ago

    ## Goal Surface daemon spawning + monitoring in the flower `/roster` UI so the operator can start orchestrator/ops/refine daemons in any project without hand-driving Solo. **v2 = one-click.** ## What's now in place (unblocked as of 2026-07-01) - **The seam exists (Brief #26, merged):** `daemon_agents` has an `expected` status + `daemon_register_expected` MCP tool; `daemon_checkin` reconciles an expected (role,project) placeholder → live (no phantom rows); `/roster` can render a daemon as "spawning". Roster health degrades gracefully when only session-link data exists. - **The spawn packet render exists (spawn-flow-ui, 973):** `/roster` already renders a filled charter + Solo spawn instructions from `SpawnPacketService`. - **The Solo-bridge answer = `solo-cli`** (the non-MCP Solo bridge). flower does NOT hold the Solo MCP, but it CAN shell out to `solo-cli` to spawn an agent + send the kickoff. ## Scope (split) **Backend bridge (this dispatch):** 1. Design the Solo-bridge spawn flow via `solo-cli`: given (project, role, optional charter override), (a) `daemon_register_expected` to show "spawning" on the roster, (b) invoke solo-cli to `spawn_agent` in the target Solo project, (c) deliver the rendered charter packet as the kickoff, (d) the daemon's own `daemon_checkin` then reconciles the expected row → live. 2. **SAFETY GATE — do NOT wire a live agent-spawn to a button without operator review.** Spawning agents is a real, sensitive action. First **report the bridge design + safety model via brief_append** (auth, how the target Solo project is resolved, guardrails: confirm before spawning into a project with active operator sessions, default new daemons to HOLD/no-loop-timer). Build + unit-test the plumbing (register-expected, packet handoff, solo-cli invocation behind a small service seam that can be faked in tests), but keep the actual live spawn behind the gate / an explicit confirm until the design is reviewed. **UI (follow-up dispatch to design 973 after #25):** `/roster` "Spawn daemon" action (project+role+ charter preview) calling the backend bridge; monitor rows (expected/live/stale/dead, context, needs_compaction, last checkin) + actions (poke / request-compaction / retire). ## Open questions to resolve in the design report - How does flower authenticate to / target the right Solo project headlessly via solo-cli? - "Go live" == arming the daemon's recurring loop timer — owned by flower or the daemon itself? ## Acceptance (backend slice) - Bridge service + `daemon_register_expected` integration, unit-tested with a faked solo-cli seam. - Design + safety model reported via `brief_append`; live-spawn gated pending review. - `php artisan test` green + pint. `Brief: #22` trailer; brief_append; brief_dispatch_complete if available. ## Provenance 2026-07-01 daemon-spawn dogfood + operator ask. Prereq (Brief #26 seam) merged; v1 copy-paste skipped.

    agent · flower-orchestrator
  28. spec snapshot 4d ago

    ## Goal Surface daemon spawning + monitoring in the flower /roster UI so the operator can start orchestrator/ops/refine daemons in any project without hand-driving Solo. **Skip the copy-paste v1; build the one-click v2** (operator decision, 2026-07-01). ## Background — the mechanism already exists server-side - `SpawnPacketService` renders the full spawn packet: the filled role charter (via `recall_charters`) + step-by-step spawn/readiness/`daemon_checkin`/handoff instructions. Charters are `PromptTemplate` rows (kind=daemon_charter), editable in the prompt-library UI. - `daemon_checkin` self-registers a daemon into the roster. Freshly-spawned agents negotiate the FULL flower MCP surface — verified 2026-07-01: orchestrator + refine daemons spawned into thedarkroom_automation registered cleanly as daemon ids 6/7. - Today flower deliberately does NOT hold the Solo MCP (the packet says "flower is only rendering this packet; it does not hold Solo"). ## v2 scope — one-click spawn via a Solo bridge - /roster gains a "Spawn daemon" action: choose project + role (+ optional charter override / draft-body preview via `SpawnPacketService::previewCharter`). - flower holds a **Solo bridge** (solo-cli or a Solo MCP handle) that can actually `spawn_agent` in the target Solo project, deliver the kickoff (charter packet), confirm readiness, then the daemon self-checks-in and appears live in the roster. - Monitor: roster rows already derive live/idle/stale/dead; add context size, needs_compaction, last checkin, and actions (poke / request-compaction / retire). - Guardrails: confirm before spawning into a project with active operator sessions; default new daemons to a HOLD posture (no autonomous loop timer) until explicitly enabled. ## Open questions - Where does the Solo bridge live and how does flower authenticate to Solo MCP headlessly? - "Go live" == arming the recurring loop timer — owned by flower or by the daemon itself? ## Provenance 2026-07-01 TDA daemon-spawn dogfood + operator request: "a way to fire those orchestrators up in those projects properly prompted/instructed on their roles" + a /roster start/monitor surface.

    system · flower-orchestrator
  29. link added 4d ago
    agent · flower-orchestrator
  30. link added 4d ago
    agent · flower-orchestrator
  31. status change 4d ago
    agent · flower-orchestrator
  32. plan proposed 4d ago

    ## Goal Surface daemon spawning + monitoring in the flower /roster UI so the operator can start orchestrator/ops/refine daemons in any project without hand-driving Solo. **Skip the copy-paste v1; build the one-click v2** (operator decision, 2026-07-01). ## Background — the mechanism already exists server-side - `SpawnPacketService` renders the full spawn packet: the filled role charter (via `recall_charters`) + step-by-step spawn/readiness/`daemon_checkin`/handoff instructions. Charters are `PromptTemplate` rows (kind=daemon_charter), editable in the prompt-library UI. - `daemon_checkin` self-registers a daemon into the roster. Freshly-spawned agents negotiate the FULL flower MCP surface — verified 2026-07-01: orchestrator + refine daemons spawned into thedarkroom_automation registered cleanly as daemon ids 6/7. - Today flower deliberately does NOT hold the Solo MCP (the packet says "flower is only rendering this packet; it does not hold Solo"). ## v2 scope — one-click spawn via a Solo bridge - /roster gains a "Spawn daemon" action: choose project + role (+ optional charter override / draft-body preview via `SpawnPacketService::previewCharter`). - flower holds a **Solo bridge** (solo-cli or a Solo MCP handle) that can actually `spawn_agent` in the target Solo project, deliver the kickoff (charter packet), confirm readiness, then the daemon self-checks-in and appears live in the roster. - Monitor: roster rows already derive live/idle/stale/dead; add context size, needs_compaction, last checkin, and actions (poke / request-compaction / retire). - Guardrails: confirm before spawning into a project with active operator sessions; default new daemons to a HOLD posture (no autonomous loop timer) until explicitly enabled. ## Open questions - Where does the Solo bridge live and how does flower authenticate to Solo MCP headlessly? - "Go live" == arming the recurring loop timer — owned by flower or by the daemon itself? ## Provenance 2026-07-01 TDA daemon-spawn dogfood + operator request: "a way to fire those orchestrators up in those projects properly prompted/instructed on their roles" + a /roster start/monitor surface.

    agent · flower-orchestrator
  33. note added 4d ago

    Operator asked for a /roster surface to start + monitor orchestrator/ops/refine daemons in any project. Skip v1 copy-paste; build v2 one-click Solo bridge.

    agent · flower-orchestrator
  34. participant joined 4d ago
    system · flower-orchestrator

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • flower-orchestrator participant · active
  • flower-backend-977 participant · active
  • system:commit-trailer participant · active
  • flower-other participant · active
  • operator:mike participant · active

trace · graph

Links

  • Commit #1218 execution
  • Commit #1190 execution
  • Commit #1193 execution
  • Commit #1180 execution
  • Scratchpad #346 execution
  • Scratchpad #351 execution

scope

Projects

  • flower · primary

dogfood · read-only

Agent’s-eye view

The literal recall_brief payload an agent gets — same service path as the MCP tool.