slice 3.5a: skills catalog — the "how to think" layer
Introduce the skills catalog: the second half of the two-layer agent
model (skills teach agents HOW to think about a problem; MCP servers
give them the ABILITY to act). Delivery via MCP resources lands in
Slice 3.5b; this slice ships the data model + API surface.
Migration 0049 extends the legacy `skills` table (from 0001_init.sql,
originally a workspace catalog of markdown snippets) with the richer
typing we need — name, when_to_use, tags, source_kind, current_version
— rather than duplicating tables. Also adds:
- skill_versions (version history for level-up promotions +
rollback; back-pointer via promoted_from
JSONB records agent_id / research artifact /
brain memory that produced it)
- template_role_skills (m2m binding skills to team-template roles
with pin_in_context + order_idx)
- agent_skills_ext (per-agent overlay: include=true adds a skill
to the bundle; include=false prunes a
template default for this specific agent)
Rust surface:
- cm_db::repo::skills_catalog with typed Skill/SkillVersion/
AgentSkillBinding structs + upsert_builtin (idempotent — bumps
version + appends to skill_versions ONLY when body changes) +
list_visible/get/get_by_name reads + template + agent binding
helpers + effective_for_agent (merges template defaults with
agent overrides, applies exclude precedence, batch-fetches skill
bodies)
- cm_api::routes::skills_catalog with:
GET /api/skills — list visible
GET /api/skills/{id} — detail
GET /api/claws/{id}/skills — effective binding (accepts
template_id + role_slot as query args to merge in template
defaults)
Follow-ups:
- Slice 3.5b: clawmates_skills MCP server exposes catalog as MCP
resources, honoring pin_in_context for auto-injection
- Slice 3.5c: seed ~40-60 builtin skills across the 6 stacks
Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
3f77370a6e
commit
1153d72d00
@@ -26,6 +26,7 @@ pub mod research_setup;
|
||||
pub mod routines;
|
||||
pub mod sessions;
|
||||
pub mod skills;
|
||||
pub mod skills_catalog;
|
||||
pub mod slack;
|
||||
pub mod structure;
|
||||
pub mod tailscale;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//! `/api/skills/*` — the skills catalog surface (Slice 3.5a).
|
||||
//! Slice 3.5b's `clawmates_skills` MCP server layers on top.
|
||||
|
||||
use axum::{
|
||||
extract::{Path, Query, State},
|
||||
Json,
|
||||
};
|
||||
use cm_db::repo::skills_catalog::{AgentSkillBinding, Skill};
|
||||
use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{ApiError, AppState, Authed};
|
||||
|
||||
pub async fn list(
|
||||
State(state): State<AppState>,
|
||||
Authed(user): Authed,
|
||||
) -> Result<Json<Vec<Skill>>, ApiError> {
|
||||
let rows =
|
||||
cm_db::repo::skills_catalog::list_visible(&state.pool, user.workspace_id.as_uuid()).await?;
|
||||
Ok(Json(rows))
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
State(state): State<AppState>,
|
||||
Authed(_user): Authed,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<Json<Skill>, ApiError> {
|
||||
let skill = cm_db::repo::skills_catalog::get(&state.pool, id)
|
||||
.await?
|
||||
.ok_or(ApiError::NotFound)?;
|
||||
Ok(Json(skill))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AgentBindingQuery {
|
||||
pub template_id: Option<Uuid>,
|
||||
pub role_slot: Option<String>,
|
||||
}
|
||||
|
||||
/// Effective skill bundle for a specific agent. When `template_id` +
|
||||
/// `role_slot` are provided, template defaults are merged with the
|
||||
/// agent's per-agent overrides; otherwise only overrides are returned.
|
||||
pub async fn effective_for_agent(
|
||||
State(state): State<AppState>,
|
||||
Authed(_user): Authed,
|
||||
Path(agent_id): Path<Uuid>,
|
||||
Query(q): Query<AgentBindingQuery>,
|
||||
) -> Result<Json<Vec<AgentSkillBinding>>, ApiError> {
|
||||
let rows = cm_db::repo::skills_catalog::effective_for_agent(
|
||||
&state.pool,
|
||||
agent_id,
|
||||
q.template_id,
|
||||
q.role_slot.as_deref(),
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(rows))
|
||||
}
|
||||
Reference in New Issue
Block a user