Skip to content

Conversation

@nikomatsakis
Copy link
Member

@nikomatsakis nikomatsakis commented Jan 17, 2026

Summary

Adds the /symposium:config slash command, allowing users to change their Symposium configuration at any time during a session.

The Config Menu

When you type /symposium:config, Symposium pauses your current session and presents an interactive menu:

## Current Configuration

**Agent:** Claude Code

**Extensions:**
1. [x] sparkle
2. [x] ferris  
3. [x] cargo

## Commands

- `SAVE` - Save changes and exit
- `CANCEL` - Discard changes and exit
- `A` or `AGENT` - Change agent
- `1`, `2`, `3` - Toggle extension on/off
- `move X to Y` - Reorder extensions

From here you can:

  • Change your AI agent - Type A to see a list of available agents and pick a new one
  • Toggle extensions - Type a number to enable/disable that extension
  • Reorder extensions - Type move 1 to 3 to change proxy ordering
  • Save or cancel - SAVE writes changes to disk; CANCEL discards them

After exiting config mode, your session resumes where you left off. Config changes take effect on the next session.

First-Time Setup

When no configuration exists, Symposium automatically enters setup mode - presenting the agent selection menu so new users can get started without manually editing config files.

Other Changes

  • Extracted symposium-ferris as a standalone agent extension
  • Updated run-mode.md documentation

Test plan

  • Unit tests for config flows (initial setup, config mode, message routing)
  • Manual testing with symposium-acp-agent run

🤖 Generated with Claude Code

nikomatsakis and others added 21 commits January 19, 2026 06:40
- Add main.rs that serves FerrisComponent over stdio
- Add [[bin]] section and [package.metadata.symposium] to Cargo.toml
- Add release-ferris.yml workflow using package-agent-extension

Co-authored-by: Claude <claude@anthropic.com>
Refactor ConfigAgent from direct async handlers to channel-based actor model:

- ConfigAgent: owns session map, handles InitialSetup/Config modes
- UberconductorActor: manages conductor lifecycle (config -> conductor mapping)
- ConductorActor: owns conductor connection, forwards prompts/notifications

Key design: NewSessionCreated pattern ensures session stored before client
response, preventing race conditions where prompts arrive before mapping exists.

Co-authored-by: Claude <claude@anthropic.com>
Add handle_session_message helper that routes messages by session state:
- Delegating sessions forward to conductor
- Config/InitialSetup sessions return method-not-supported error
- Unknown sessions return unknown-session error

Also adds get_session_id helper to extract session ID from MessageCx.

Co-authored-by: Claude <claude@anthropic.com>
All messages from conductors to clients now flow through ConfigAgent
via the new MessageToClient variant. This enables ConfigAgent to:
- Inject session updates (e.g., slash command registration)
- Intercept or modify messages as needed

The ConductorActor no longer holds a direct client_cx reference.

Co-authored-by: Claude <claude@anthropic.com>
Add handle_message_to_client helper that uses MatchMessage to intercept
SessionNotification messages from conductors. When the notification contains
an AvailableCommandsUpdate, injects the /symposium:config command before
forwarding to the client.

Co-authored-by: Claude <claude@anthropic.com>
- Add CONFIG_SLASH_COMMAND const to avoid string duplication
- Add is_config_command() to detect when prompt is the slash command
- Add enter_config_mode() to transition session to Config state
- Preserve conductor handle in return_to for returning after config
- Send welcome message when entering config mode

Co-authored-by: Claude <claude@anthropic.com>
The actor implements a text-based menu system for configuration:
- Main menu shows current agent + proxies with toggle/reorder commands
- Agent selection fetches available agents from registry
- Proper spawn pattern using cx.spawn() instead of tokio::spawn
- Actor sends output back to ConfigAgent via unbounded channel

Co-authored-by: Claude <claude@anthropic.com>
Cleaner and more robust than manual string splitting.

Co-authored-by: Claude <claude@anthropic.com>
Replace ConfigState enum with natural async loops:
- main_menu_loop() shows menu and dispatches
- agent_selection_loop() is called and returns when done
- ActorContext holds shared state passed through functions

The control flow IS the state machine - much cleaner.

Co-authored-by: Claude <claude@anthropic.com>
Cleaner organization - ConfigModeActor now owns all its behavior
as methods rather than standalone functions with ctx parameter.

Co-authored-by: Claude <claude@anthropic.com>
More explicit about what each action does.

Co-authored-by: Claude <claude@anthropic.com>
- Done: exit the menu loop
- Redisplay: show menu again (state changed)
- Continue: just wait for input (invalid command)

Avoids repeating the full menu on typos.

Co-authored-by: Claude <claude@anthropic.com>
- Rename SessionAgent → ConfigAgent to match implementation
- Add three-actor architecture diagram (ConfigAgent, Uberconductor, Conductor)
- Add sequence diagrams for new session flow, prompt routing, config mode
- Document actual config mode UI commands (SAVE, CANCEL, toggle, move)
- Explain MessageToClient routing pattern

Co-authored-by: Claude <claude@anthropic.com>
When entering config mode via /symposium:config, the conductor is now
paused to prevent it from processing messages from the downstream agent.

The protocol:
1. ConfigAgent sends Pause to conductor with channel for resume_tx
2. Conductor creates oneshot, sends resume_tx back, awaits resume_rx
3. ConfigModeActor holds resume_tx until exit
4. Dropping resume_tx signals conductor to resume

This ensures clean separation - the downstream agent is completely
idle while the user is configuring.

Co-authored-by: Claude <claude@anthropic.com>
- Add tests.rs for ConfigAgent with three test cases:
  - test_no_config_initial_setup: verifies initial setup flow
  - test_new_session_with_config: verifies elizacp integration
  - test_config_mode_entry: verifies /symposium:config command

- Make registry mockable for tests via with_injected_agents()
  to bypass network calls during testing

- ConfigAgent sends initial AvailableCommandsUpdate with
  /symposium:config on session creation (fixes case where
  downstream agent doesn't send commands)

Co-authored-by: Claude <claude@anthropic.com>
- Export ConfigAgent from lib.rs crate root
- Remove old config.rs (ConfigurationAgent) - superseded by ConfigAgent
- The run command now uses ConfigAgent which handles:
  - Configured state: spawns conductors and delegates sessions
  - Unconfigured state: runs initial setup wizard
  - Runtime /symposium:config command for configuration changes

Co-authored-by: Claude <claude@anthropic.com>
- Remove InitialSetup session state - no longer needed
- ConfigModeActor now takes Option<SymposiumUserConfig>:
  - Some(config): shows main config menu (existing behavior)
  - None: shows welcome + agent selection, creates default config
- When no config exists, enter config mode directly with None
- Pass config as parameter to methods instead of storing in self
- Update test to verify full initial setup flow

This simplifies the architecture by having one unified config flow
instead of separate InitialSetup and Config states.

Co-authored-by: Claude <claude@anthropic.com>
- Switch to 1-based indexing for extensions and agents
- Agent selection now uses a markdown table
- Extensions shown as numbered list with strikethrough for disabled
- Commands section uses bullet list
- Add 'move X to start' and 'move X to end' commands
- Fix error message for empty extension list
- Rename 'proxies' to 'extensions' in UI

Co-authored-by: Claude <claude@anthropic.com>
Without this flag, sparkle-mcp runs as an MCP server instead of an
ACP proxy. The conductor sends _proxy/initialize to proxy components,
but a plain MCP server doesn't understand this message, causing the
conductor to deadlock waiting for a response that never comes.

Co-authored-by: Claude <claude@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant