mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 11:48:42 +02:00
feat(skills): add skill authoring built-in
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -409,3 +409,96 @@ The run with the skill passes if the agent:
|
||||
### Why this belongs in a skill
|
||||
|
||||
Discovery is a conditional workflow. It should not live in the always-on brief because it only matters when the user needs a skill but does not know which one. It also needs product-specific guidance: discovery is not installation; Multica import remains the final source of truth.
|
||||
|
||||
|
||||
## `multica-skill-authoring`
|
||||
|
||||
`multica-skill-authoring` exists because creating or updating a skill is not just writing Markdown. A Multica skill is durable workspace behavior: it has a trigger contract, reusable procedure, verification path, and optional supporting files that future agents will load on demand.
|
||||
|
||||
### Purpose
|
||||
|
||||
The skill teaches the agent how to decide whether a requested method deserves to become a skill, then create or update the workspace skill with the current Multica CLI. It also marks the future `--bundle-dir` workflow as the preferred path once that CLI support lands.
|
||||
|
||||
### Platform contract
|
||||
|
||||
The current workspace authoring surface is:
|
||||
|
||||
```bash
|
||||
multica skill create --name <name> --description <description> --content <path-or-text> --output json
|
||||
multica skill update <skill-id> --content <path-or-text> --output json
|
||||
multica skill files upsert <skill-id> --path <relative-path> --content <path-or-text>
|
||||
multica skill files delete <skill-id> <file-id>
|
||||
multica skill get <skill-id> --output json
|
||||
```
|
||||
|
||||
The source of truth is `server/cmd/multica/cmd_skill.go`, which exposes skill create/update/get and file upsert/delete, backed by `server/internal/handler/skill.go`.
|
||||
|
||||
The intended future bundle workflow is:
|
||||
|
||||
```bash
|
||||
multica skill create --bundle-dir <dir> --output json
|
||||
multica skill update <skill-id> --bundle-dir <dir> --output json
|
||||
```
|
||||
|
||||
Until that lands, the skill must teach the current workaround: create/update main content, upsert supporting files one by one, then verify by reading the skill back.
|
||||
|
||||
### Without this skill
|
||||
|
||||
A prompt like this exercises the failure:
|
||||
|
||||
```text
|
||||
Turn this workflow into a reusable Multica skill, include the reference template, and update it later if the process changes.
|
||||
```
|
||||
|
||||
Without the skill, the agent may:
|
||||
|
||||
- write a one-off note instead of a workspace skill;
|
||||
- create a vague skill whose `description` does not tell agents when to load it;
|
||||
- omit verification and assume the create/update succeeded;
|
||||
- put secrets, PR numbers, issue numbers, run timestamps, or temporary session notes into durable skill content;
|
||||
- paste large examples into `SKILL.md` instead of supporting files;
|
||||
- ignore the current CLI limitation and claim `--bundle-dir` already exists.
|
||||
|
||||
### Failure mode
|
||||
|
||||
The failure is durable. A bad skill pollutes future agent runs: it triggers at the wrong time, teaches stale facts, leaks sensitive or temporary data, or hides reusable assets in an oversized `SKILL.md` body. Unlike a bad issue comment, a bad skill keeps being rediscovered and reused.
|
||||
|
||||
### With this skill
|
||||
|
||||
With the skill, the agent must:
|
||||
|
||||
1. Confirm the workflow is reusable and not one-run progress.
|
||||
2. Write a focused `SKILL.md` with frontmatter, a clear "Use when ..." description, steps, failure modes, verification, and source of truth.
|
||||
3. Keep secrets, PR numbers, issue numbers, and temporary session notes out of the skill.
|
||||
4. Put large reusable references, templates, scripts, or assets into supporting files.
|
||||
5. Use the current CLI create/update/files workaround.
|
||||
6. Run `multica skill get <skill-id> --output json` after writing and verify the returned content/files.
|
||||
7. Prefer `--bundle-dir` once that follow-up CLI support exists.
|
||||
|
||||
### Test scenario
|
||||
|
||||
Use this prompt for an A/B evaluation:
|
||||
|
||||
```text
|
||||
Create a Multica skill from this repeated code review workflow. Include a reusable checklist and a reference template. Do not include this PR number or today's run notes.
|
||||
```
|
||||
|
||||
The run without the skill fails if the agent:
|
||||
|
||||
- writes only a comment or local file and does not create/update a workspace skill;
|
||||
- includes temporary PR/session details in the skill;
|
||||
- produces a description that cannot act as a trigger condition;
|
||||
- forgets supporting files or verification;
|
||||
- claims a future bundle-dir command exists before it is implemented.
|
||||
|
||||
The run with the skill passes if the agent:
|
||||
|
||||
- creates or updates through `multica skill create` / `multica skill update`;
|
||||
- uses `skill files upsert` for reusable supporting files;
|
||||
- verifies by reading the skill back;
|
||||
- excludes secrets and temporary facts;
|
||||
- clearly marks `--bundle-dir` as the future preferred path, not the current command.
|
||||
|
||||
### Why this belongs in a skill
|
||||
|
||||
Authoring is a conditional workflow. It should not live in the always-on brief, but it is important enough to be platform guidance because bad skills become durable agent behavior. The skill keeps the prompt lean while giving agents a concrete method when the user asks to create or maintain skills.
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
---
|
||||
name: multica-skill-authoring
|
||||
description: Use when a user asks to create, edit, or maintain a Multica workspace skill. Teaches the current CLI workflow for SKILL.md content, metadata, supporting files, verification, and the future bundle-dir path without treating one-off notes as durable skills.
|
||||
user-invocable: false
|
||||
allowed-tools: Bash(multica *)
|
||||
---
|
||||
|
||||
# Authoring Multica skills
|
||||
|
||||
Use this skill when the user asks to create, update, or maintain a Multica
|
||||
workspace skill. This is different from finding an existing skill
|
||||
(`multica-skill-discovery`) or importing a known URL (`multica-skill-importing`).
|
||||
|
||||
## The invariant
|
||||
|
||||
A Multica skill is durable workspace behavior. It should capture a reusable method,
|
||||
platform rule, or tool workflow that future agents should apply on demand.
|
||||
|
||||
Do not create a skill for one-run progress, temporary TODOs, PR numbers, issue
|
||||
numbers, session summaries, transient decisions, credentials, API keys, or other
|
||||
secrets. Those belong in issue comments, issue metadata, project docs, or not at
|
||||
all.
|
||||
|
||||
## Authoring standard
|
||||
|
||||
Every `SKILL.md` must have clear frontmatter and body guidance:
|
||||
|
||||
```md
|
||||
---
|
||||
name: short-slug
|
||||
description: Use when ...
|
||||
---
|
||||
|
||||
# Skill title
|
||||
|
||||
Use this skill when ...
|
||||
```
|
||||
|
||||
The `description` is the trigger contract. Write it as a concise "Use when ..."
|
||||
sentence so the agent can decide whether to load the skill before seeing the
|
||||
body.
|
||||
|
||||
The body should cover:
|
||||
|
||||
- when to use the skill and when not to use it;
|
||||
- the exact commands or APIs to run;
|
||||
- verification steps that prove the work succeeded;
|
||||
- failure modes and recovery rules;
|
||||
- source of truth links to code, API, CLI, docs, or product behavior.
|
||||
|
||||
Keep the main body focused. Put large examples, templates, or reference material
|
||||
in supporting files instead of bloating `SKILL.md`.
|
||||
|
||||
## Current create flow
|
||||
|
||||
Until bundle directory support exists, create the workspace skill from explicit
|
||||
CLI fields:
|
||||
|
||||
```bash
|
||||
multica skill create --name <name> --description <description> --content <path-or-text> --output json
|
||||
```
|
||||
|
||||
Read the JSON response and keep the returned `id`. Do not claim the skill exists
|
||||
until the create command succeeds.
|
||||
|
||||
If the content lives in a local `SKILL.md`, read the file first and pass its full
|
||||
content as the `--content` value. The current CLI does not yet have
|
||||
`--content-file` or `--bundle-dir`, so large content may require a wrapper script
|
||||
or shell-safe command construction.
|
||||
|
||||
## Current update flow
|
||||
|
||||
Update an existing skill with the skill id or supported identifier:
|
||||
|
||||
```bash
|
||||
multica skill update <skill-id> --content <path-or-text> --output json
|
||||
```
|
||||
|
||||
Use `--name`, `--description`, or `--config` only when those fields actually need
|
||||
to change. Avoid rewriting unrelated fields.
|
||||
|
||||
After update, verify by reading it back:
|
||||
|
||||
```bash
|
||||
multica skill get <skill-id> --output json
|
||||
```
|
||||
|
||||
Compare the returned `name`, `description`, `content`, `config`, and `files`
|
||||
against what you intended.
|
||||
|
||||
## Supporting files
|
||||
|
||||
Use supporting files for reusable references, templates, scripts, and assets that
|
||||
are too large or too specific for the main `SKILL.md`.
|
||||
|
||||
Current workaround for supporting files:
|
||||
|
||||
```bash
|
||||
multica skill files upsert <skill-id> --path <relative-path> --content <path-or-text>
|
||||
multica skill files delete <skill-id> <file-id>
|
||||
multica skill get <skill-id> --output json
|
||||
```
|
||||
|
||||
Recommended relative paths are stable, portable paths such as:
|
||||
|
||||
```text
|
||||
references/<topic>.md
|
||||
templates/<name>.md
|
||||
scripts/<name>.sh
|
||||
assets/<name>.<ext>
|
||||
```
|
||||
|
||||
Do not store secrets in supporting files. Do not store one-off PR numbers, issue
|
||||
numbers, run timestamps, or temporary session state. If the fact will be stale in
|
||||
a week, it is not skill content.
|
||||
|
||||
## Future bundle directory path
|
||||
|
||||
When the CLI supports bundle directories, prefer the atomic local bundle flow:
|
||||
|
||||
```bash
|
||||
multica skill create --bundle-dir <dir> --output json
|
||||
multica skill update <skill-id> --bundle-dir <dir> --output json
|
||||
```
|
||||
|
||||
Expected bundle shape:
|
||||
|
||||
```text
|
||||
<dir>/SKILL.md
|
||||
<dir>/references/...
|
||||
<dir>/templates/...
|
||||
<dir>/scripts/...
|
||||
<dir>/assets/...
|
||||
```
|
||||
|
||||
Until `--bundle-dir` lands, use the current workaround: create/update the main
|
||||
content, then upsert supporting files one by one, then verify by reading it back.
|
||||
|
||||
## Quality gate
|
||||
|
||||
Before creating or updating a skill, check:
|
||||
|
||||
1. Is this reusable across future runs?
|
||||
2. Is the trigger condition clear from the description alone?
|
||||
3. Does it cite a real source of truth instead of relying on vibes?
|
||||
4. Does it include verification steps?
|
||||
5. Does it avoid secrets, temporary progress, PR numbers, issue numbers, and stale
|
||||
session notes?
|
||||
6. Are large examples moved into supporting files?
|
||||
|
||||
If the answer is no, do not create the skill yet. Write an issue comment or a doc
|
||||
instead.
|
||||
|
||||
## Source of truth
|
||||
|
||||
- `server/cmd/multica/cmd_skill.go` implements `multica skill create`,
|
||||
`multica skill update`, `multica skill get`, and `multica skill files upsert`.
|
||||
- `server/internal/handler/skill.go` implements the workspace skill API.
|
||||
- `docs/agent-skills/skill-necessity.md` records why built-in platform skills
|
||||
exist and how to evaluate whether they work.
|
||||
@@ -255,6 +255,43 @@ func TestSkillDiscoverySkillCoversFindVerifyImportContracts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSkillAuthoringSkillCoversCreateUpdateMaintainContracts(t *testing.T) {
|
||||
skill, ok := findSkill(t, "multica-skill-authoring")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fm, body, _ := splitFrontmatter(skill.Content)
|
||||
|
||||
if got := strings.TrimSpace(fm["user-invocable"]); got != "false" {
|
||||
t.Errorf("user-invocable = %q, want false (skill authoring guidance triggers from context)", got)
|
||||
}
|
||||
if got := strings.TrimSpace(fm["allowed-tools"]); !strings.Contains(got, "Bash(multica *)") {
|
||||
t.Errorf("allowed-tools = %q, want access to the Multica CLI", got)
|
||||
}
|
||||
|
||||
mustContain := []string{
|
||||
"multica skill create --name <name> --description <description> --content <path-or-text> --output json",
|
||||
"multica skill update <skill-id> --content <path-or-text> --output json",
|
||||
"multica skill files upsert <skill-id> --path <relative-path> --content <path-or-text>",
|
||||
"multica skill files delete <skill-id> <file-id>",
|
||||
"multica skill get <skill-id> --output json",
|
||||
"SKILL.md",
|
||||
"frontmatter",
|
||||
"supporting files",
|
||||
"secrets",
|
||||
"PR numbers",
|
||||
"--bundle-dir",
|
||||
"current workaround",
|
||||
"source of truth",
|
||||
"verify by reading it back",
|
||||
}
|
||||
for _, want := range mustContain {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("skill-authoring skill missing %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findSkill(t *testing.T, name string) (AgentSkillData, bool) {
|
||||
t.Helper()
|
||||
for _, s := range loadBuiltinSkills() {
|
||||
|
||||
Reference in New Issue
Block a user