Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/config/sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct AgentSoundOverrides {
pub kilo: AgentSoundSetting,
pub qodercli: AgentSoundSetting,
pub maki: AgentSoundSetting,
pub muse: AgentSoundSetting,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize)]
Expand Down Expand Up @@ -140,6 +141,7 @@ impl AgentSoundOverrides {
Some(Agent::Kilo) => self.kilo,
Some(Agent::Qodercli) => self.qodercli,
Some(Agent::Maki) => self.maki,
Some(Agent::Muse) => self.muse,
None => AgentSoundSetting::Default,
}
}
Expand Down Expand Up @@ -179,6 +181,7 @@ impl Default for AgentSoundOverrides {
kilo: AgentSoundSetting::Default,
qodercli: AgentSoundSetting::Default,
maki: AgentSoundSetting::Default,
muse: AgentSoundSetting::Default,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/detect/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ const BUNDLED_MANIFESTS: &[(&str, &str)] = &[
("kimi", include_str!("manifests/kimi.toml")),
("kiro", include_str!("manifests/kiro.toml")),
("maki", include_str!("manifests/maki.toml")),
("muse", include_str!("manifests/muse.toml")),
("opencode", include_str!("manifests/opencode.toml")),
("pi", include_str!("manifests/pi.toml")),
("qodercli", include_str!("manifests/qodercli.toml")),
Expand Down
80 changes: 80 additions & 0 deletions src/detect/manifests/muse.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
id = "muse"
version = "2026.08.06.1"
min_engine_version = 2
updated_at = "2026-08-06T00:00:00Z"
aliases = ["muse-code", "muse-cli"]

# Evidence: Live pane reads via `herdr pane read <pane> --source detection --format text`
# captured from Muse Code 0.1.0 (muse-spark-1.2-contributor) in herdr.
#
# Idle (prompt ready) bottom chrome:
# ── Voice input (⌥ + v to start) ───── ... ─
# ⟩
# ───────────────────────────────────── ... ─
# muse-spark-1.2-contributor · xhigh · ~/Developer/herdr · YOLO
# The prompt is a single `⟩` (U+27E9) on its own line. The status footer always
# contains `·` separators and the model path `~/Developer/herdr` (cwd) plus
# `YOLO` when launched with --yolo.
#
# Working (agent running tools/commands):
# ◆ Running command · <description> (0s · esc to interrupt)
# └ (ctrl+b to send to background)
# ── Voice input (⌥ + v to start) ─────
# ⟩ ...
# Any live activity line contains `esc to interrupt`. This is the invariant
# between idle and working – idle footer is `YOLO`/`xhigh` without `esc`.
#
# Blocked (approval) – Muse shows tool approval when not in --yolo. The
# footer gains acceptance hints. We encode generic blocked signals so --yolo
# idle is not misclassified. These patterns were not observed in the initial
# capture and are kept lower priority / generic.
#

[[rules]]
id = "pick_request_blocked"
state = "blocked"
priority = 950
region = "bottom_non_empty_lines(5)"
visible_blocker = true
contains = ["Enter to select"]

[[rules]]
id = "working_esc_interrupt"
state = "working"
priority = 900
region = "bottom_non_empty_lines(8)"
visible_working = true
contains = ["esc to interrupt"]
not = [{ contains = ["Enter to select"] }]
Comment thread
greptile-apps[bot] marked this conversation as resolved.

[[rules]]
id = "blocked_approval"
state = "blocked"
priority = 850
region = "bottom_non_empty_lines(8)"
visible_blocker = true
any = [
{ contains = ["Do you want to proceed?"] },
{ contains = ["Allow", "Always allow"] },
{ contains = ["waiting for approval", "run this command?"], any = [{ contains = ["proceed"] }] },
{ contains = ["(y) (enter)"] },
{ contains = ["do you want to allow"] },
]
Comment thread
coderabbitai[bot] marked this conversation as resolved.

[[rules]]
id = "idle_prompt"
state = "idle"
priority = 700
region = "bottom_non_empty_lines(5)"
visible_idle = true
line_regex = ['^\s*⟩\s*$']
not = [{ contains = ["esc to interrupt"] }]
Comment thread
coderabbitai[bot] marked this conversation as resolved.

[[rules]]
id = "idle_status_fallback"
state = "idle"
priority = 500
region = "bottom_non_empty_lines(3)"
visible_idle = true
contains = ["YOLO"]
not = [{ contains = ["esc to interrupt"] }]
18 changes: 16 additions & 2 deletions src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ pub enum Agent {
Kilo,
Qodercli,
Maki,
Muse,
}

impl Agent {
pub const ALL: [Self; 21] = [
pub const ALL: [Self; 22] = [
Self::Pi,
Self::Claude,
Self::Codex,
Expand All @@ -87,9 +88,10 @@ impl Agent {
Self::Kilo,
Self::Qodercli,
Self::Maki,
Self::Muse,
];

pub const SCREEN_MANIFEST_AGENTS: [Self; 19] = [
pub const SCREEN_MANIFEST_AGENTS: [Self; 20] = [
Self::Pi,
Self::Claude,
Self::Codex,
Expand All @@ -109,6 +111,7 @@ impl Agent {
Self::Kilo,
Self::Qodercli,
Self::Maki,
Self::Muse,
];
}

Expand All @@ -135,6 +138,7 @@ pub fn agent_label(agent: Agent) -> &'static str {
Agent::Kilo => "kilo",
Agent::Qodercli => "qodercli",
Agent::Maki => "maki",
Agent::Muse => "muse",
}
}

Expand Down Expand Up @@ -167,6 +171,7 @@ pub fn interactive_agent_executable(agent: Agent) -> &'static str {
Agent::Kilo => "kilo",
Agent::Qodercli => "qodercli",
Agent::Maki => "maki",
Agent::Muse => "muse",
}
}

Expand Down Expand Up @@ -203,6 +208,7 @@ fn lookup_agent(name: &str) -> Option<Agent> {
"kilo" | "kilo-code" | "kilo code" => Some(Agent::Kilo),
"qodercli" | "qoderclicn" | "qoder" | "qodercn" => Some(Agent::Qodercli),
"maki" => Some(Agent::Maki),
"muse" | "muse-bin" | "muse-code" | "muse-cli" => Some(Agent::Muse),
_ => None,
}
}
Expand Down Expand Up @@ -710,6 +716,10 @@ mod tests {
assert_eq!(identify_agent("kilo"), Some(Agent::Kilo));
assert_eq!(identify_agent("kilo-code"), Some(Agent::Kilo));
assert_eq!(identify_agent("maki"), Some(Agent::Maki));
assert_eq!(identify_agent("muse"), Some(Agent::Muse));
assert_eq!(identify_agent("muse-bin"), Some(Agent::Muse));
assert_eq!(identify_agent("muse-code"), Some(Agent::Muse));
assert_eq!(identify_agent("muse-cli"), Some(Agent::Muse));
}

#[test]
Expand Down Expand Up @@ -778,6 +788,7 @@ mod tests {
(Agent::Kilo, "kilo"),
(Agent::Qodercli, "qodercli"),
(Agent::Maki, "maki"),
(Agent::Muse, "muse"),
];
assert_eq!(expected.len(), Agent::ALL.len());
for (agent, executable) in expected {
Expand Down Expand Up @@ -820,6 +831,9 @@ mod tests {
assert_eq!(identify_agent("zsh"), None);
assert_eq!(identify_agent("vim"), None);
assert_eq!(identify_agent("node"), None);
assert_eq!(identify_agent("museum"), None);
assert_eq!(identify_agent("muse-helper"), None);
assert_eq!(identify_agent("muser"), None);
}

#[test]
Expand Down
4 changes: 4 additions & 0 deletions website/agent-detection/index.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ path = "kiro.toml"
id = "maki"
path = "maki.toml"

[[agents]]
id = "muse"
path = "muse.toml"

[[agents]]
id = "opencode"
path = "opencode.toml"
Expand Down
80 changes: 80 additions & 0 deletions website/agent-detection/muse.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
id = "muse"
version = "2026.08.06.1"
min_engine_version = 2
updated_at = "2026-08-06T00:00:00Z"
aliases = ["muse-code", "muse-cli"]

# Evidence: Live pane reads via `herdr pane read <pane> --source detection --format text`
# captured from Muse Code 0.1.0 (muse-spark-1.2-contributor) in herdr.
#
# Idle (prompt ready) bottom chrome:
# ── Voice input (⌥ + v to start) ───── ... ─
# ⟩
# ───────────────────────────────────── ... ─
# muse-spark-1.2-contributor · xhigh · ~/Developer/herdr · YOLO
# The prompt is a single `⟩` (U+27E9) on its own line. The status footer always
# contains `·` separators and the model path `~/Developer/herdr` (cwd) plus
# `YOLO` when launched with --yolo.
#
# Working (agent running tools/commands):
# ◆ Running command · <description> (0s · esc to interrupt)
# └ (ctrl+b to send to background)
# ── Voice input (⌥ + v to start) ─────
# ⟩ ...
# Any live activity line contains `esc to interrupt`. This is the invariant
# between idle and working – idle footer is `YOLO`/`xhigh` without `esc`.
#
# Blocked (approval) – Muse shows tool approval when not in --yolo. The
# footer gains acceptance hints. We encode generic blocked signals so --yolo
# idle is not misclassified. These patterns were not observed in the initial
# capture and are kept lower priority / generic.
#

[[rules]]
id = "pick_request_blocked"
state = "blocked"
priority = 950
region = "bottom_non_empty_lines(5)"
visible_blocker = true
contains = ["Enter to select"]

[[rules]]
id = "working_esc_interrupt"
state = "working"
priority = 900
region = "bottom_non_empty_lines(8)"
visible_working = true
contains = ["esc to interrupt"]
not = [{ contains = ["Enter to select"] }]

[[rules]]
id = "blocked_approval"
state = "blocked"
priority = 850
region = "bottom_non_empty_lines(8)"
visible_blocker = true
any = [
{ contains = ["Do you want to proceed?"] },
{ contains = ["Allow", "Always allow"] },
{ contains = ["waiting for approval", "run this command?"], any = [{ contains = ["proceed"] }] },
{ contains = ["(y) (enter)"] },
{ contains = ["do you want to allow"] },
]

[[rules]]
id = "idle_prompt"
state = "idle"
priority = 700
region = "bottom_non_empty_lines(5)"
visible_idle = true
line_regex = ['^\s*⟩\s*$']
not = [{ contains = ["esc to interrupt"] }]

[[rules]]
id = "idle_status_fallback"
state = "idle"
priority = 500
region = "bottom_non_empty_lines(3)"
visible_idle = true
contains = ["YOLO"]
not = [{ contains = ["esc to interrupt"] }]
Loading