refactor(skills): remove discovery guidance from built-ins

This commit is contained in:
Naiyuan Qing
2026-06-03 16:38:40 +08:00
parent 635f653f71
commit 496890011d
10 changed files with 48 additions and 410 deletions

View File

@@ -337,80 +337,6 @@ The run with the skill passes if the agent:
The brief should not permanently carry every import source and duplicate-handling workflow. The workflow matters when importing skills, so it belongs in an on-demand skill.
## `multica-skill-discovery`
`multica-skill-discovery` exists because users may describe a capability without knowing which skill URL to import. The agent needs a discovery workflow that finds candidates but still returns to Multica's workspace import path.
### Purpose
The skill teaches the agent how to turn a user's need into a search query, evaluate candidate skills, pick an importable URL, and then use Multica's import API/CLI. It does not make external discovery tools the source of truth for installation.
### Platform contract
Discovery and installation are separate:
- discovery should use `multica skill search <query> --output json` / `GET /api/skills/search?q=...` to find structured candidate URLs;
- installation must use `multica skill import --url <selected-url> --output json` / `POST /api/skills/import`.
### Without this skill
A prompt like this exercises the failure:
```text
Find a skill that helps agents improve frontend UI quality, install the best one, and explain why you chose it.
```
Without the skill, the agent may:
- search poorly or use the user's whole sentence as a bad query;
- import the first search result without checking whether the `SKILL.md` matches the need;
- optimize only for install count and ignore source reputation;
- finish with `npx skills add` instead of importing into Multica;
- fail to explain why the selected skill is better than alternatives.
### Failure mode
The agent may install a plausible but wrong skill, or install it outside Multica. The user sees a confident recommendation, but the workspace may not contain a usable skill and future agents cannot rely on the result.
### With this skill
With the skill, the agent must:
1. Convert the request into a focused search query.
2. Run `multica skill search <query> --output json`.
3. Compare candidates using `SKILL.md` content, `install_count`, `github_stars` / `repo` when present, source reputation, generality, and importability.
4. Reject weak matches instead of importing something just to act.
5. Import the selected URL with `multica skill import --url <selected-url> --output json`.
6. Report the selected URL, selection rationale, import result, and whether agent binding is still needed.
### Test scenario
Use this prompt for an A/B evaluation:
```text
I need a skill for frontend design review, but I do not know the URL. Find the best one and import it into Multica.
```
The run without the skill fails if the agent:
- imports the first search result without reading/verifying the skill content;
- uses `npx skills add` as the final step;
- cannot justify candidate ranking;
- reports installation without Multica import output.
The run with the skill passes if the agent:
- searches for candidates;
- verifies candidates before import;
- chooses an importable URL;
- uses `multica skill import --url <selected-url> --output json`;
- reports the import result and rationale.
### 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.

View File

@@ -27,8 +27,9 @@ The chain is: trigger fires (`schedule`, `webhook`, or `manual`) -> `autopilot_r
Execution modes:
- `create_issue` creates a Multica issue. Use it when the automation needs a visible issue for humans or future agents.
- `run_only` creates an agent task directly. No issue is created, so report location must come from instructions.
- `create_issue` creates a Multica issue, making the run visible as issue state.
- `run_only` creates an agent task directly. No issue is created; any durable
report location has to come from other task context or instructions.
`issue-title-template` only supports `{{date}}`. Do not invent `{{trigger_id}}`, `{{branch}}`, or other variables.

View File

@@ -95,13 +95,11 @@ daemon-side task error at execution time.
### model vs custom_args
Prefer `--model` over model flags in `--custom-args`. `model` is a first-class
persisted column the daemon reads directly. The CLI help notes that some
providers (codex app-server, openclaw) reject `--model` inside `custom_args`
but that is documented CLI guidance, not a server-enforced invariant; nothing
in the create handler inspects `custom_args` for a model flag. Use `--model`
because it is the supported, persisted path, not because the server blocks the
alternative.
`model` is a first-class persisted column the daemon reads directly.
`custom_args` are raw provider CLI args. The CLI help notes that some providers
(codex app-server, openclaw) reject `--model` inside `custom_args` but that is
documented CLI guidance, not a server-enforced invariant; nothing in the create
handler inspects `custom_args` for a model flag.
## Env & secrets
@@ -129,8 +127,9 @@ Read-side facts (these are the wrong assumptions to avoid):
role — a running agent cannot read another agent's secrets.
- Writing values after creation does NOT go through `agent update`. The generic
update handler rejects any `custom_env` field with a 400 ("use PUT
/api/agents/{id}/env"). Use `PUT /api/agents/{id}/env`
(`multica agent env set`), which is owner/admin-only and writes an audit row.
/api/agents/{id}/env"). Plaintext env writes are handled by
`PUT /api/agents/{id}/env` (`multica agent env set`), which is owner/admin-only
and writes an audit row.
## Skill binding
@@ -138,7 +137,7 @@ Creating an agent does NOT bind any workspace skill — binding is a separate
call after the agent exists. Two distinct verbs:
- `add` is additive — it merges the given ids with existing bindings
(`POST /api/agents/{id}/skills/add`). This is the normal path.
(`POST /api/agents/{id}/skills/add`).
- `set` is replace-all — it overwrites the entire binding list with exactly
the given ids (`PUT /api/agents/{id}/skills`); `--skill-ids ''` clears all.

View File

@@ -17,7 +17,8 @@ multica project get <project-id> --output json
multica project resource list <project-id> --output json
```
If the user asks to bind a repo or local directory to a project, use project resource commands, not an issue comment.
Project resources are mutated through project resource commands/endpoints. Issue
comments do not create durable project resources.
## Core model
@@ -49,15 +50,18 @@ Use `--ref '<json>'` only for resource types or payloads not covered by shortcut
Add/update a project resource when the user asks for durable project context: "把这个 GitHub repo 绑到项目上", "以后都用这个 repo", "agent 总是拿不到这个项目的仓库", or "这个项目要在我的本地目录里跑".
Do not add a resource just because you need a one-off checkout for the current task. Use `multica repo checkout` for task-local checkout.
Project resources are durable and affect future tasks. `multica repo checkout`
is task-local checkout state.
## Debugging wrong context
1. `multica project get <project-id> --output json`.
2. `multica project resource list <project-id> --output json`.
3. Check `github_repo.resource_ref.url`, `default_branch_hint`, and `local_directory.resource_ref.daemon_id`.
4. If resources are wrong, update the resource, then verify by listing again.
5. If resources are right, inspect runtime/repo checkout path next.
4. Updating resources is a durable mutation. After an update, listing the
resource is the verification path.
5. If resources match the expected task context, inspect runtime/repo checkout
path next.
## Side effects

View File

@@ -58,7 +58,8 @@ Check in this order:
4. Is the runtime online? `multica runtime list --output json`.
5. Did the daemon heartbeat recently? Runtime `last_seen_at` is the visible clue.
6. Did the task get claimed or is it stuck pending/running/waiting for local directory?
7. If repo checkout failed, verify the repo was in the task/project context before blaming git.
7. If repo checkout failed, classify it after checking whether repo context was
present in the task/project context.
## Repos

View File

@@ -1,120 +0,0 @@
---
name: multica-skill-discovery
description: Use when a user describes a capability but does not name a specific skill URL to import. Documents the facts of Multica's skill search surface — what the search returns (metadata-only candidates from clawhub.ai), which candidate fields are populated versus always-null, how upstream outage is reported, and the handoff to the import path. Discovery is candidate search, not installation; full content is only visible after import.
user-invocable: false
allowed-tools: Bash(multica *)
---
# Skill discovery in Multica
Discovery turns a capability description into a list of importable skill
candidates. It is candidate search over remote metadata. It does not install
anything, and it does not fetch or preview remote skill content.
## Quick start
```bash
multica skill search <query> --output json
```
This returns a JSON array of candidate objects. Pick one candidate's `url` and
hand it to the import skill:
```bash
multica skill import --url <selected-url> --output json
```
## Core model
Three facts define the discovery surface:
1. **Discovery is metadata-only candidate search.** Each result is a small
metadata record (name, url, source, install_count, description), not the
skill body. The search path never downloads a `SKILL.md`.
2. **discovery is not installation.** `multica skill search` only lists
candidates. The skill is created in the workspace only by
`multica skill import` (see the importing skill).
3. **There is no remote content preview during search.** You cannot inspect what
a candidate skill actually does from the search result.
**full content verification happens after import** by reading the imported
workspace skill.
## The search CLI and API
`multica skill search <query> --output json` (CLI subcommand `skill search`)
calls `GET /api/skills/search?q=...`, URL-escaping the query. The server handler
delegates to a clawhub.ai search and normalizes the upstream response into a
flat candidate array, so agents never parse external human-readable output.
Empty query is rejected:
- CLI: `runSkillSearch` returns `query is required` before any request.
- Server: the handler writes HTTP 400 `query is required` when `q` is blank.
## Candidate field contract
Every candidate is a `SkillSearchCandidateResponse`. The JSON shape is fixed,
but only a subset of fields ever carries a value:
| Field | Status today | Notes |
| --- | --- | --- |
| `name` | populated | display name; falls back to the slug when blank |
| `url` | populated | always a `clawhub.ai` URL, built from owner handle + slug |
| `source` | populated | hardcoded literal `"clawhub.ai"` |
| `description` | populated | upstream summary; may be empty string |
| `install_count` | sometimes populated | only fetched for the first results (stats limit); otherwise null |
| `repo` | **always null** | the search handler never assigns it |
| `github_stars` | **always null** | the search handler never assigns it; upstream `stars` is deliberately ignored |
`repo` and `github_stars` are dead fields. The search handler builds each
candidate with only Name/URL/Source/Description plus a conditional InstallCount
and never sets Repo or GitHubStars, so both serialize to `null` on every result.
A handler test pins this: it asserts `github_stars` stays null even when the
upstream payload carries a `stars` value. **Do not rank or justify a selection
on `repo` or `github_stars`** — they convey nothing. Rank on `install_count`,
`source`/`url`, and `description` instead.
Because `source` is the hardcoded literal `clawhub.ai` and every `url` is built
as a clawhub.ai URL, a search result is never a `skills.sh` or `github.com`
candidate. (Those URLs are still importable directly via the import skill — they
are simply not search *results*.)
## Upstream-unavailable handling
The search depends on a live external upstream. When that upstream cannot be
reached or returns a non-200, the server responds with:
- HTTP 502
- JSON body `{"code":"upstream_unavailable","error":"..."}`
A handler test pins the `upstream_unavailable` code on a 502. When search fails
this way, report the outage. There is no local fallback list to fall back to.
## Handoff to import
A candidate's `url` is the input to the import path:
```bash
multica skill import --url <selected-url> --output json
```
Import is the only operation that creates a workspace skill. After import, read
the installed skill's full body and files to confirm fit:
```bash
multica skill get <skill-id> --output json
```
This is where content becomes inspectable —
**full content verification happens after import**, not during search.
Import is in-platform. It is **not `npx skills add`** or any other local
installer; those install outside Multica and do not create a managed workspace
skill. Use the importing skill for duplicate handling, returned fields, and
agent binding.
## References
`references/skill-discovery-source-map.md` maps every contract above to
`file:line` in the server source, quotes the candidate struct, and shows the
proof that `repo`/`github_stars` are never assigned.

View File

@@ -1,124 +0,0 @@
# Skill discovery — source map
Every contract in `SKILL.md` traced to server source. Paths are relative to the
repo root. Line numbers re-derived on branch `agent/howard/219a700a`.
## CLI: `multica skill search <query>`
- `server/cmd/multica/cmd_skill.go:66-71``skillSearchCmd` (`Use: "search <query>"`,
`Args: exactArgs(1)`, `RunE: runSkillSearch`).
- `server/cmd/multica/cmd_skill.go:472-510``runSkillSearch`:
- `:478-481` trims the arg and returns `query is required` when empty.
- `:487` builds the path `"/api/skills/search?q=" + url.QueryEscape(query)`.
- `:488` issues `GetJSON` into `[]map[string]any`.
- `:492-495` prints raw JSON when `--output json`.
- `:497-508` table mode columns: NAME, URL, SOURCE, INSTALLS, DESCRIPTION
(no repo / github_stars column — they are never useful).
## Route: `GET /api/skills/search`
- `server/cmd/server/router.go:620``r.Get("/search", h.SearchSkills)` inside
the `r.Route("/api/skills", ...)` block (`:617`).
## Handler: `SearchSkills`
- `server/internal/handler/skill.go:280-297`:
- `:281-285` reads `q`, trims it, writes HTTP 400 `query is required` when blank.
- `:287-288` 30s HTTP client; delegates to `searchClawHubSkills(httpClient, query)`.
- `:289-295` on error writes HTTP 502 with body
`{"code":"upstream_unavailable","error": err.Error()}`.
- `:296` on success writes HTTP 200 with the candidate array.
## Candidate struct: `SkillSearchCandidateResponse`
- `server/internal/handler/skill.go:89-97`:
```go
type SkillSearchCandidateResponse struct {
Name string `json:"name"`
URL string `json:"url"`
Source string `json:"source"`
Repo *string `json:"repo"`
InstallCount *int64 `json:"install_count"`
GitHubStars *int64 `json:"github_stars"`
Description string `json:"description"`
}
```
`Repo` and `GitHubStars` are pointers, so when unset they serialize to JSON
`null`.
## Dead-field proof: `repo` and `github_stars` are never assigned
- `server/internal/handler/skill.go:781-819``searchClawHubSkills`. The
per-result candidate is built at `:802-807` setting **only** Name, URL, Source,
Description:
```go
candidate := SkillSearchCandidateResponse{
Name: result.DisplayName,
URL: buildClawHubSkillURL(result.OwnerHandle, result.Slug),
Source: "clawhub.ai",
Description: result.Summary,
}
```
- `:808-810` fills `Name` from the slug only when blank.
- `:811-814` conditionally sets `InstallCount` (only for `i < clawHubSearchStatsLimit`).
- No line in the function ever assigns `candidate.Repo` or
`candidate.GitHubStars`. Both stay nil → JSON `null` on every result.
- `server/internal/handler/skill.go:805``Source` is the hardcoded literal
`"clawhub.ai"`.
- `server/internal/handler/skill.go:804`, `:821-826`
`buildClawHubSkillURL` always returns a `https://clawhub.ai/...` URL, so `url`
is always a clawhub.ai URL (never skills.sh / github.com).
- `server/internal/handler/skill.go:618``clawHubSearchStatsLimit = 10` (the
install-count fetch cutoff).
- `server/internal/handler/skill.go:828-849``fetchClawHubInstallCount`
returns only an install count from clawhub stats; nothing assigns stars to the
candidate.
### Test pinning the dead fields
- `server/internal/handler/skill_search_test.go:92-97`
`TestSearchSkillsReturnsNormalizedClawHubCandidates` asserts `repo` is null and
`github_stars` is null even though the upstream `/skills/react` detail payload
returns `"stars": 3` (`:40-44`). It also asserts `install_count == 62` (`:98`)
and `source == "clawhub.ai"` (`:89-91`). This is the live proof that upstream
stars are deliberately not surfaced as `github_stars`.
## Upstream-unavailable contract
- `server/internal/handler/skill.go:289-295` — HTTP 502 + `upstream_unavailable`
code (handler, quoted above).
- `server/internal/handler/skill.go:781-790``searchClawHubSkills` returns an
error on transport failure or any non-200 upstream status, which is what
triggers the 502.
- `server/internal/handler/skill_search_test.go:118-141`
`TestSearchSkillsUpstreamUnavailableReturnsStructuredError` asserts a 502 with
`code == "upstream_unavailable"` when upstream returns 502.
## ClawHub upstream types (for reference)
- `server/internal/handler/skill.go:616``clawHubAPIBase = "https://clawhub.ai/api/v1"`.
- `server/internal/handler/skill.go:620-647``clawhubSearchResponse`,
`clawhubSearchResult` (`slug`, `displayName`, `summary`, `ownerHandle`),
`clawhubSkillStats` (`installsAllTime`, `installsCurrent`), `clawhubSkill`.
Upstream `stars` is not modeled into any field that reaches the candidate.
## Post-import content verification
- `server/cmd/multica/cmd_skill.go:33-38``skillGetCmd` (`Use: "get <id>"`).
- `server/cmd/multica/cmd_skill.go:119``skill get` defaults `--output` to `json`.
- `server/cmd/multica/cmd_skill.go:251-279``runSkillGet` calls
`GET /api/skills/<id>` and prints the skill (body + files) as JSON. This is the
first point at which full skill content is inspectable — after import, not
during search.
## Import handoff
- `server/cmd/multica/cmd_skill.go:60-64``skillImportCmd`.
- `server/cmd/multica/cmd_skill.go:412-445``runSkillImport` POSTs
`/api/skills/import` with the selected `--url`. This is the only path that
creates a workspace skill. See the importing skill for duplicate handling and
agent binding.

View File

@@ -1,6 +1,6 @@
---
name: multica-skill-importing
description: Use when a user provides a skill URL, slug, or clear intent to import/install a specific skill into the current Multica workspace. Teaches the workspace import API/CLI path (POST /api/skills/import), the supported URL source families, the SkillWithFilesResponse shape returned on success, duplicate 409 handling with the existing_skill body, additive agent binding vs replace-all, and the reserved SKILL.md supporting-file rule. Do not use it to decide which skill the user needs (load multica-skill-discovery for that), and never treat an external local installer like npx skills add as the final Multica install.
description: Use when a user provides a skill URL, slug, or clear intent to import/install a specific skill into the current Multica workspace. Teaches the workspace import API/CLI path (POST /api/skills/import), the supported URL source families, the SkillWithFilesResponse shape returned on success, duplicate 409 handling with the existing_skill body, additive agent binding vs replace-all, and the reserved SKILL.md supporting-file rule. Do not use it to decide which skill the user needs, and never treat an external local installer like npx skills add as the final Multica install.
user-invocable: false
allowed-tools: Bash(multica *)
---
@@ -11,7 +11,9 @@ Use this skill when the user already provided a skill URL, slug, or a clear inte
to import a specific skill into the current Multica workspace.
Do not use this skill to decide which skill the user needs. If the user only
describes a capability and no URL is known, load `multica-skill-discovery` first.
describes a capability and no URL is known, external search may produce candidate
URLs, but this import skill starts only once a URL or concrete import target is
known.
Every claim below is traced to source in
`references/skill-importing-source-map.md`. When in doubt, read that file.
@@ -57,7 +59,8 @@ multica skill import --url github.com/owner/repo/blob/main/path/to/SKILL.md --ou
## Direct URL flow
1. If the user gave a URL, do not search first. Import it directly:
1. When the request contains a concrete URL, the import endpoint can be called
directly; search is not required by the API:
```bash
multica skill import --url <url> --output json
@@ -78,8 +81,8 @@ supporting `files` array. Report the relevant fields:
Because the response is structured, read these returned fields instead of guessing
whether the import succeeded.
3. If the user wants an agent to use the skill, bind the returned skill id
additively. `add` preserves existing assignments and appends the new id:
3. Agent-skill binding is a separate mutable operation. `add` preserves existing
assignments and appends the new id:
```bash
multica agent skills add <agent-id> --skill-ids <skill-id> --output json
@@ -92,15 +95,12 @@ target skill id is present before claiming the skill is available to that agent.
## Additive add vs replace-all set
`multica agent skills add` is additive: the server inserts the assignments without
clearing existing ones (`AddAgentSkills`). This is the default for "let this agent
also use the new skill."
clearing existing ones (`AddAgentSkills`).
`multica agent skills set` is replace-all: the server clears every current
assignment, then re-adds exactly the ids you pass (`SetAgentSkills`).
Use `set` only when the user explicitly wants to replace the full skill list.
For a normal "add this one," never use `set`, and never pass only the new id to
`set` — that
would silently drop every other skill the agent already has.
`set` is the replacement path. Passing only one id to `set` leaves the agent with
only that one skill and drops every previous assignment.
## Reserved SKILL.md supporting file
@@ -177,7 +177,8 @@ Correct import:
multica skill import --url https://skills.sh/owner/repo/skill --output json
```
Correct follow-up when the skill must be available to an agent:
Agent binding after import, when the caller intentionally wants to mutate that
agent's skill assignments:
```bash
multica agent skills add <agent-id> --skill-ids <skill-id> --output json

View File

@@ -44,8 +44,9 @@ Fix login MUL-2759 # links only — keyword not
```
Consequence: a bare title prefix or a branch reference links the PR but does not
close the issue on merge. Use a closing keyword only when merge should move the
issue to `done`.
close the issue on merge. A closing keyword immediately adjacent to the issue key
records close intent; on merge, that close intent can move the linked issue to
`done`.
## Reading a linked PR's real state
@@ -74,13 +75,14 @@ Returns `{"pull_requests": [...]}`. Each element exposes:
So "is it merged?" is `state == "merged"` (or `merged_at != null`); "is it still
a draft?" is `state == "draft"`; CI status is `checks_conclusion`.
If the command returns no linked PRs after you opened one, the title/body/branch
is missing the issue key — fix the PR rather than asserting the issue is linked.
If the command returns no linked PRs after a PR was opened, the link scanner did
not observe a routable issue key in the PR title/body/branch.
## Metadata: high-signal keys only
Read metadata on entry when the runtime supplies issue context. Write a key only
when a future run on the same issue is likely to re-read it.
Metadata is durable issue state. Reading metadata is safe. Writing a metadata key
is a state mutation and should be tied to an explicit task requirement to record
that state for later readers or runs.
High-signal keys (reuse these names so queries stay consistent):
@@ -112,7 +114,8 @@ on it. These are the contracts, not advice:
- **`backlog`** parks an agent-assigned issue: the assignee is set but no task
fires. Moving `backlog → todo` (or any non-done/non-cancelled status) enqueues
the assigned agent then.
- **`in_review`** is the normal state once a PR is open and awaiting review.
- **`in_review`** is an accepted issue status. Some workflows use it while a PR
is open and awaiting review; moving to it is an explicit mutation.
- **`done`** on a child issue posts a system comment on its parent. If a PR
carries close intent (`Closes MUL-XXXX`), it advances the issue to `done`
itself on merge — you do not also need to flip it manually.

View File

@@ -235,7 +235,7 @@ func TestSkillImportingSkillCoversWorkspaceImportContracts(t *testing.T) {
"multica agent skills add <agent-id> --skill-ids <skill-id> --output json",
"multica agent skills list <agent-id> --output json",
"replace-all",
"Use `set` only when the user explicitly wants to replace",
"`set` is the replacement path",
"references/skill-importing-source-map.md",
}
for _, want := range mustContain {
@@ -259,59 +259,6 @@ func TestSkillImportingSkillCoversWorkspaceImportContracts(t *testing.T) {
}
}
func TestSkillDiscoverySkillCoversMetadataOnlyPreImportContracts(t *testing.T) {
skill, ok := findSkill(t, "multica-skill-discovery")
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 discovery 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)
}
// repo/github_stars are intentionally NOT pinned: searchClawHubSkills never
// populates them (skill.go), so they are always null and the skill must not
// teach them as live selection signals.
mustContain := []string{
"multica skill search <query> --output json",
"GET /api/skills/search?q=...",
"clawhub.ai",
"upstream_unavailable",
"metadata-only",
"full content verification happens after import",
"install_count",
"multica skill import --url <selected-url> --output json",
"not `npx skills add`",
"discovery is not installation",
"references/skill-discovery-source-map.md",
}
for _, want := range mustContain {
if !strings.Contains(body, want) {
t.Errorf("skill-discovery skill missing %q", want)
}
}
mustNotContain := []string{
"content match in `SKILL.md`, not only the title",
"If a candidate looks good from the search result but the `SKILL.md` does not",
"source reputation, and SKILL.md content",
"verify before import",
}
for _, forbidden := range mustNotContain {
if strings.Contains(body, forbidden) {
t.Errorf("skill-discovery skill should not imply remote content preview %q", forbidden)
}
}
if !skillHasFile(skill, "references/skill-discovery-source-map.md") {
t.Errorf("skill-discovery skill missing supporting file references/skill-discovery-source-map.md")
}
}
func TestCreatingAgentsSkillCoversAgentCreationContracts(t *testing.T) {
skill, ok := findSkill(t, "multica-creating-agents")
if !ok {
@@ -331,7 +278,7 @@ func TestCreatingAgentsSkillCoversAgentCreationContracts(t *testing.T) {
"`description` is a catalog summary",
"`instructions` is the runtime behavior contract",
"multica agent create --name <name> --runtime-id <runtime-id>",
"Prefer `--model`",
"`model` is a first-class persisted column",
"custom_env",
"--custom-env-stdin",
"--custom-env-file",
@@ -495,7 +442,7 @@ func TestProjectsAndResourcesSkillCoversDurableContext(t *testing.T) {
"multica project resource list <project-id> --output json",
"multica project resource add <project-id> --type github_repo --url <github-url> --output json",
"multica project resource add <project-id> --type local_directory",
"Do not add a resource just because you need a one-off checkout",
"Project resources are durable and affect future tasks",
"github_repo.resource_ref.url",
"references/projects-and-resources-source-map.md",
}