Planck.Agent.SkillUsage (Planck.Agent v0.1.7)

Copy Markdown View Source

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_namespec.name || spec.type, e.g. "Builder", "orchestrator"
  • agent_typespec.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

ranked_names(project_dir, team_name, agent_name, skills, n)

@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_use(project_dir, team_name, agent_name, agent_type, skill_name)

@spec record_use(Path.t(), String.t(), String.t(), String.t(), String.t()) :: :ok

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.

top_n(project_dir, team_name, agent_name, n)

@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.

top_n_for_orchestrators(project_dir, team_name, n)

@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.