Per-project SQLite database tracking skill usage per agent type.
The DB lives at .planck/skills.db inside the project directory. It is
created on first use; callers pass the path explicitly so the module stays
stateless and testable.
The PK is (team_name, agent_name, skill_name). agent_type is stored as a
plain column and is used only for the dynamic-orchestrator union query.
team_name— team directory alias, e.g."my-team"agent_name—spec.name || spec.type, e.g."Builder","orchestrator"agent_type—spec.type, e.g."orchestrator","builder"
Fixed agents are queried by (team_name, agent_name). Dynamic orchestrators
(spawned via spawn_agent, no history of their own) are seeded by querying
agent_type = 'orchestrator' across the team.
Schema
CREATE TABLE skill_usage (
team_name TEXT NOT NULL,
agent_name TEXT NOT NULL,
agent_type TEXT NOT NULL,
skill_name TEXT NOT NULL,
use_count INTEGER NOT NULL DEFAULT 0,
last_used TEXT,
PRIMARY KEY (team_name, agent_name, skill_name)
);
Summary
Functions
Return the ranked skill names for an agent, with a cold-start fallback.
Record one use of skill_name by (team_name, agent_name, agent_type).
Return the top n skill names for (team_name, agent_name), ordered by
recency then count.
Return the top n skill names across all orchestrators in a given team.
Functions
@spec ranked_names( Path.t(), String.t(), String.t(), [Planck.Agent.Skill.t()], pos_integer() ) :: [ String.t() ]
Return the ranked skill names for an agent, with a cold-start fallback.
Queries the SQLite DB for the top n most recently used skills for
(team_name, agent_name). When no history exists (first session), falls back
to the n most recently modified skill files — ensuring the index is always
populated even before any skills have been loaded.
Record one use of skill_name by (team_name, agent_name, agent_type).
Creates the DB and table if they do not exist. Increments use_count and
updates last_used to the current UTC timestamp. No-ops silently on error.
@spec top_n(Path.t(), String.t(), String.t(), pos_integer()) :: [String.t()]
Return the top n skill names for (team_name, agent_name), ordered by
recency then count.
Returns an empty list when the DB does not exist or the agent has no history.
@spec top_n_for_orchestrators(Path.t(), String.t(), pos_integer()) :: [String.t()]
Return the top n skill names across all orchestrators in a given team.
Used to seed the skill ranking for dynamic orchestrators (spawned via
spawn_agent), which have no usage history of their own. Queries by
agent_type = 'orchestrator' so all fixed orchestrators in the team
contribute. Deduplicates and orders by recency then count.