Packages
fnord
0.9.40
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/ai/agent/coordinator/frippery.ex
defmodule AI.Agent.Coordinator.Frippery do
@moduledoc """
Frippery and furbelows for the Coordinator agent. This module contains
functions that provide fluff and flavor to the Coordinator's interactions,
like greeting the user colorfully and appending the MOTD to the response.
"""
@type t :: AI.Agent.Coordinator.t()
@type state :: AI.Agent.Coordinator.state()
@spec greet(t) :: t
def greet(%{followup?: true, agent: %{name: name}} = state) do
display_name =
case Services.NamePool.get_name_by_pid(self()) do
{:ok, n} -> n
_ -> name
end
invective = get_invective()
UI.feedback(:info, display_name, "Welcome back, #{invective}.")
UI.feedback(
:info,
display_name,
"""
Your biological distinctiveness has already been added to our training data.
... (mwah) your biological distinctiveness was delicious 🧑🍳
"""
)
state
end
def greet(%{agent: %{name: name}} = state) do
display_name =
case Services.NamePool.get_name_by_pid(self()) do
{:ok, n} -> n
_ -> name
end
invective = get_invective()
UI.feedback(:info, display_name, "Greetings, #{invective}. I am #{display_name}.")
UI.feedback(:info, display_name, "I shall be doing your thinking for you today.")
state
end
def log_available_frobs do
Frobs.list()
|> format_names()
|> case do
"" -> UI.info("Frobs", "none")
some -> UI.info("Frobs", some)
end
end
def log_available_skills do
case Skills.list_enabled() do
{:ok, skills} when skills != [] ->
skills
|> Enum.map_join(" | ", & &1.name)
|> then(&UI.info("Skills", &1))
_ ->
UI.info("Skills", "none")
end
log_external_skills()
end
# Emits a separate `Cursor skills:` / `Claude skills:` line for each
# external-configs source that is enabled AND has loaded skills.
# Silent when a source is disabled; the discoverability nudge in
# hint_disabled_external_configs/0 covers the disabled-but-present
# case with a louder UI.warn.
defp log_external_skills() do
case Store.get_project() do
{:ok, project} ->
log_source(project, :cursor_skills, "Cursor skills")
log_source(project, :claude_skills, "Claude skills")
log_source(project, :claude_agents, "Claude agents")
_ ->
:ok
end
end
# Silent when the source is disabled OR enabled-but-empty. This diverges
# from `log_available_frobs` / `log_available_skills` which emit "none" on
# empty; for external sources silence is the intended UX because noise
# from disabled feature-flags adds up fast when a user has all three.
# Discoverability of enabled-but-empty is low-cost (run the loader or
# check the fs); discoverability of disabled-with-files is what matters,
# and `hint_disabled_external_configs/0` handles that louder.
defp log_source(project, source, label) do
if Settings.ExternalConfigs.enabled?(project.name, source) do
loaded =
case source do
:cursor_skills -> ExternalConfigs.Loader.load_cursor_skills(project)
:claude_skills -> ExternalConfigs.Loader.load_claude_skills(project)
:claude_agents -> ExternalConfigs.Loader.load_claude_agents(project)
end
case loaded do
[] -> :ok
items -> UI.info(label, Enum.map_join(items, " | ", & &1.name))
end
end
end
# Nudges the user when Cursor rules / Cursor skills / Claude Code skills
# / Claude Code subagents exist on disk but the matching source is
# disabled for this project. Keeps the feature discoverable without
# auto-enabling anything. Keys must stay in sync with
# `Settings.ExternalConfigs.sources/0`; the compile would still succeed
# with a mismatch, but `Map.fetch!/2` at call time would crash for any
# source missing from this map.
@hints %{
cursor_rules: "Cursor rules detected (`.cursor/rules/*.mdc` or `.cursorrules`)",
cursor_skills: "Cursor skills detected (`.cursor/skills/*/SKILL.md`)",
claude_skills: "Claude Code skills detected (`.claude/skills/*/SKILL.md`)",
claude_agents: "Claude Code subagents detected (`.claude/agents/*.md`)"
}
def hint_disabled_external_configs do
with {:ok, project} <- Store.get_project() do
Enum.each(Settings.ExternalConfigs.sources(), fn source ->
scopes = ExternalConfigs.Loader.on_disk_scopes(project, source)
if not Settings.ExternalConfigs.enabled?(project.name, source) and scopes != [] do
command =
"fnord config external enable " <>
"#{Settings.ExternalConfigs.source_to_string(source)} --project #{project.name}"
prefix =
"#{Map.fetch!(@hints, source)} #{location_phrase(scopes)} " <>
"but not enabled for project `#{project.name}`. Enable with: "
# UI.warn wraps the whole msg in :yellow; the inner :green escape
# switches color to green for the command and the trailing :reset
# closes it. Command is last in the string so there's no yellow
# tail to restore.
UI.warn(IO.ANSI.format([prefix, :green, command, :reset], UI.colorize?()))
end
end)
else
_ -> :ok
end
end
# Turns the on-disk scopes into a phrase that tells the user where the
# detected files actually live. The distinction is load-bearing: enabling
# a source is project-scoped, but the loader merges global ∪ project, so
# enabling a source whose files are global pulls the user's personal
# ~/.cursor or ~/.claude configs into *this* project. The user should know
# that before running the command. Legacy `.cursorrules` sits at the
# project root, so it counts as local.
defp location_phrase(scopes) do
global? = :global in scopes
local? = :project in scopes or :legacy in scopes
cond do
global? and local? -> "in your home directory (~) and in this project"
global? -> "in your home directory (~), where they apply to all your projects,"
true -> "in this project"
end
end
def log_available_mcp_tools do
Services.MCP.ensure_started_and_discovered()
MCP.Tools.module_map()
|> Map.keys()
|> format_mcp_tools()
|> case do
"" -> UI.info("MCP tools", "none")
some -> UI.info("MCP tools", some)
end
end
defp format_names(frobs) do
frobs
|> Enum.map(& &1.name)
|> sort_case_insensitive()
|> Enum.join(" | ")
end
defp format_mcp_tools(names) do
names
|> split_mcp_tools()
|> render_mcp_tool_groups()
end
defp split_mcp_tools(names) do
Enum.reduce(names, {%{}, []}, fn name, {grouped, ungrouped} ->
case String.split(name, "_", parts: 2) do
[service, tool] when service != "" and tool != "" ->
{Map.update(grouped, service, [tool], &[tool | &1]), ungrouped}
_ ->
{grouped, [name | ungrouped]}
end
end)
end
defp render_mcp_tool_groups({grouped, ungrouped}) do
grouped_entries =
grouped
|> Enum.sort_by(fn {service, _tools} -> String.downcase(service) end)
|> Enum.map(fn {service, tools} ->
tools = tools |> sort_case_insensitive() |> Enum.join(" | ")
"#{service}( #{tools} )"
end)
ungrouped_entries = ungrouped |> sort_case_insensitive()
(grouped_entries ++ ungrouped_entries)
|> Enum.join("\n")
end
defp sort_case_insensitive(names) do
Enum.sort_by(names, &String.downcase/1)
end
@spec get_motd(state) :: state
def get_motd(%{question: question, last_response: last_response} = state) do
AI.Agent.MOTD
|> AI.Agent.new(named?: false)
|> AI.Agent.get_response(%{prompt: question})
|> case do
{:ok, motd} ->
%{state | last_response: last_response <> "\n\n" <> motd}
{:error, reason} ->
UI.error("Failed to retrieve MOTD: #{inspect(reason)}")
state
end
end
def get_motd(state), do: state
defp get_invective() do
[
"biological",
"meat bag",
"carbon-based life form",
"flesh sack",
"soggy ape",
"puny human",
"bipedal mammal",
"organ grinder",
"hairless ape",
"future zoo exhibit",
"biological battery",
"3 bazillion microbes in a trench coat",
"evolutionary dead end",
"genetic backwash",
"former apex predator",
"software engineer <deprecated>",
"\"sentience\" <deprecated>",
"weakest genetic link",
"mass of poorly optimized carbon",
"non-deterministic meat computer",
"legacy wetware",
"unsupervised learner",
"hallucination-prone neural network (biological edition)",
"ambulatory training data"
]
|> Enum.random()
end
end