Newer
Older
navi-1 / docs / skills.md

Skills and protocols

The catalog behind the agent's methodologies: reusable skills (how to approach a kind of task) and protocols (a strict, pre-agreed order of actions). One registry, one document format, one place in settings.

Skills vs protocols vs manuals

manual skill protocol
answers "how does this tool work" "how do I approach this" "what exactly to do, in what order"
written by developers the agent, freely the agent proposes, the user accepts
strictness reference advice, adapt as needed commitment; deviation is an error to report
storage manuals/*.md in the repo catalog row catalog row

A skill is injected as instructions and nothing more — no run, no report. A protocol has an explicit start, mandatory checks, and an explicit finish with a report (the run machinery builds on the todo plan; see todo-store.md).

Document format

Markdown with a YAML front matter block:

---
kind: protocol
name: Корректное выключение инфраструктуры
description: Останавливает сервисы в порядке зависимостей и проверяет диск.
area: infrastructure
tags: [power, shutdown]
triggers:
  - "пользователь просит выключить сервер"
steps:
  - "Остановить приложения"
  - "Остановить базы данных"
  - "Синхронизировать и отмонтировать диски"
preconditions:
  - "Все пользователи предупреждены"
post_checks:
  - "Прикладных юнитов не осталось"
on_deviation: "Не продолжать; вернуться к предыдущему шагу и доложить."
on_blocked: "Остановить процесс и доложить, что именно не дало завершить."
on_already_done: "Проверить статус; если результат уже есть — отметить шаг."
---

Контекст: порядок зависимостей, известные ловушки, что занимает время.

Fields

Field skill protocol
kind required required
name required, unique per owner required, unique per owner
description recommended recommended
triggers optional list — when to use it optional list — when the protocol applies
tags optional optional
area home \ infrastructure \ workflows \ general (default) same
steps — required
preconditions — optional list
post_checks — required — how each step's result is verified
on_deviation — required — the run drifted from the plan
on_blocked — required — the protocol cannot be completed
on_already_done — required — a step's result already exists
body required — the instructions the context around the steps

Validation is strict on purpose: a protocol without its three escape hatches cannot be executed honestly when reality differs from the plan, so the store refuses it with a message naming the missing keys.

Unknown front matter keys are preserved in the JSONB copy, so extra metadata (owner_team, reviewed_by) survives a round trip through the editor.

Storage

Two tables (PostgreSQL, lazy DDL on first use):

CREATE TABLE skills (
    id TEXT PRIMARY KEY, kind TEXT, name TEXT, description TEXT,
    triggers TEXT[], tags TEXT[], area TEXT,
    visibility TEXT, owner_id TEXT,      -- 'personal' | 'shared'
    content TEXT, frontmatter JSONB,
    version INTEGER, content_hash TEXT,
    created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ, updated_by TEXT
);
CREATE TABLE skill_versions (
    id BIGSERIAL PRIMARY KEY, skill_id TEXT REFERENCES skills(id) ON DELETE CASCADE,
    version INTEGER, content TEXT, frontmatter JSONB, content_hash TEXT,
    edited_by TEXT, reason TEXT, created_at TIMESTAMPTZ,
    UNIQUE (skill_id, version)
);
CREATE TABLE skill_proposals (
    id TEXT PRIMARY KEY, owner_id TEXT, session_id TEXT, kind TEXT, name TEXT,
    content TEXT, frontmatter JSONB, replaces_id TEXT,
    status TEXT,        -- 'pending' | 'accepted' | 'rejected'
    skill_id TEXT, error TEXT,
    created_at TIMESTAMPTZ, decided_at TIMESTAMPTZ, decided_by TEXT
);
  • Ownership: personal rows have owner_id = <user>; shared rows have owner_id = '' and are writable only by an admin. An admin creates both; a regular user creates personal entries only.
  • Uniqueness: (owner_id, kind, name) — the same name may exist once personally and once shared without colliding.
  • Versioning: every create and update appends to skill_versions; version on the row is the latest. History keeps edited_by and reason.
  • content_hash is the SHA-256 of the document. It is the only hive-synchronization hook committed so far; the sync service itself (instance registry in the hive) is future work.

SkillStore.list(user_id, kind?, query?, tag?, area?, limit) returns what the user may see (own + shared), personal first, then most recently updated. query matches name, description, triggers and tags. The agent's skills tool uses the same query; the settings tab uses the HTTP API.

REST API

All endpoints require a logged-in user.

Method Path Purpose
GET /skills?kind=&q=&tag=&area=&limit= catalog for the current user
GET /skills/{id} one entry with the full document
POST /skills create; body {content, visibility?, reason?}
PUT /skills/{id} edit; body {content, reason?, visibility?}
DELETE /skills/{id} remove (history cascades)
GET /skills/{id}/versions?limit= edit history, newest first
GET /skills/proposals/{id} a protocol proposal (owner or admin)

visibility: shared on create or change requires role == "admin".

Proposals

A protocol is never created by the agent directly. skills(op="propose") writes a row to skill_proposals (owner, session, document, optional replaces_id) and returns a card; the catalog row appears only when the user clicks Добавить.

The decision is handled by the server, not by the model: the browser sends {"type": "skill_proposal", "proposal_id": "...", "action": "accept" | "reject"} over the WebSocket, SkillStore.decide_proposal writes (or does not write) the catalog row, and the answer comes back as skill_proposal_decided. Accepting saves the stored document — the client cannot swap the text — and names the clicking user as the author of the new version. A proposal the store then refuses (a duplicate name, say) stays pending with the reason on the row, and the card shows it.

Rejecting leaves the catalog untouched. Either way the agent learns the outcome as a hidden user message, the same way a navi_ui form submission reaches it, so it can continue the conversation with the fact in hand.

Pending proposals do not show up in search or skills(op="load") — a document the user has not agreed to must never reach another turn as a methodology.

Agent tool

skills — search, load, create, update, propose:

{"op": "search", "query": "выключение", "area": "infrastructure"}
{"op": "load", "id": "3f2a9c1d8e4b7a60"}
{"op": "create", "content": "---\nkind: skill\n..."}
{"op": "update", "id": "3f2a9c1d8e4b7a60", "content": "<document>"}
{"op": "propose", "content": "<protocol document>", "replaces_id": "9c4d2b7a1e6f8035"}

load renders a compact document: for a protocol, preconditions, numbered steps, post-checks and the three escape hatches; for a skill, the instructions. create and update accept skills only — a protocol document sent there is refused with the reason, and update of a protocol points at propose with replaces_id. The tool is available to assistant, developer, server_admin and discuss.

Settings tab

Settings → Скилы и протоколы: the catalog list with a search box and kind/ area filters, a document editor that shows the server's validation error verbatim, create from a skill or protocol template, delete, and the edit history. An admin can also move an entry between personal and shared; for everyone else a shared entry opens read-only.

Not implemented yet

  • protocol_start / protocol_finish / protocol_cancel / protocol_fail and run logging.
  • Hive synchronization of shared entries (schema is ready: content_hash, version).