Skip to main content

code-reviewer

Four-layer skill composition, skill marketplaces, the self-learning loop

Source facts

Repository
agentscope-ai/agentscope-java
Last source activity
November 1, 2026 at 08:41
Detected SKILL.md language
English
Stars
6,218
Forks
1,554

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
11 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
title
Skill
description
Four-layer skill composition, skill marketplaces, the self-learning loop
zh_link
/v2/zh/docs/harness/skill
A skill is a packaged capability: a directory with a `SKILL.md` (purpose + instructions the agent reads), optional reference docs, scripts, samples. Hand it to the agent and it will use it when relevant. Harness lets you install skills from two places: - **Skill marketplaces** — Git repo, Nacos, MySQL, classpath, custom stores - **Workspace** — `workspace/skills/` is shared by everyone; `<userId>/skills/` isolates per user Both sources are active simultaneously — no need to choose one. On top of that you can enable a **self-learning loop**: the agent drafts skills → review gate → background curator tidies up. A skill directory looks like: ``` code-reviewer/ ├── SKILL.md # required — YAML frontmatter (name + description) + instructions for the agent ├── references/ # optional — long-form docs the agent reads on demand │ └── style-guide.md └── scripts/ # optional — executable scripts the agent can shell out to └── run-checks.sh ``` Save `SKILL.md` as UTF-8. A byte order mark (BOM) before the opening `---` is supported. Close the YAML frontmatter with an unindented line containing only `---` and optional spaces or tabs. A `---` inside a description or an indented YAML block scalar remains part of the metadata. Skill names must match `^[a-z0-9][a-z0-9-]*$` and be at most 64 characters (lowercase letters, digits, and hyphens only — no underscores or dots), following the industry naming standard for Agent Skills. Names are used verbatim as directory keys and skill identifiers, so non-conforming names are rejected when the skill is constructed or loaded. SKILL.md format: ```markdown --- name: code-reviewer description: Use when the user asks for code review, style feedback, or PR audits. --- # Code Reviewer Steps: 1. Read `references/style-guide.md` for project conventions. 2. Run `scripts/run-checks.sh <target-path>` and summarize the output. ``` ## A quick example Plug in your team's skill repo and the agent can use it immediately: ```java HarnessAgent agent = HarnessAgent.builder() .name("assistant") .model(model) .workspace(workspace) .skillRepository(new GitSkillRepository("https://github.com/your-org/team-skills.git")) .build(); ``` During reasoning, the agent sees skills from the repo and calls `load_skill_through_path` for whichever one it needs. ## Marketplace stores `skillRepository(...)` is the unified entry point — pass any store. ### Git ```xml <dependency> <groupId>io.agentscope</groupId> <artifactId>agentscope-extensions-skill-git-repository</artifactId> <version>${agentscope.version}</version> </dependency> ``` ```java .skillRepository(new GitSkillRepository("https://github.com/your-org/team-skills.git")) ``` By default, each read does a lightweight remote check, pulling only when HEAD changed. If the repo has a `skills/` subdirectory, that's the root; otherwise the repo root is. To control sync timing yourself: `new GitSkillRepository(url, false)`, then call `repo.sync()` manually. ### Nacos ```xml <dependency> <groupId>io.agentscope</groupId> <artifactId>agentscope-extensions-nacos-skill</artifactId> <version>${agentscope.version}</version> </dependency> ``` ```java NacosSkillRepository market = new NacosSkillRepository(aiService, "namespace"); HarnessAgent.builder() .skillRepository(market) .build(); ``` Best for online distribution + change subscription. `market` is `AutoCloseable`; close it on shutdown to release subscriptions. ### MySQL ```java MysqlSkillRepository registry = MysqlSkillRepository.builder(dataSource) .databaseName("agentscope") .skillsTableName("skills") .createIfNotExist(true) .writeable(true) .build(); HarnessAgent.builder() .skillRepository(registry) .build(); ``` Common for platform-side skill management. `writeable(true)` lets agents write back; pass `false` for read-only distribution. ### Classpath Ship skills inside your JAR: ``` src/main/resources/skills/ └── code-reviewer/ └── SKILL.md ``` ```java .skillRepository(new ClasspathSkillRepository("skills")) ``` Works with both standard JARs and Spring Boot fat JARs. ### Multiple stores Call `skillRepository(...)` multiple times; later ones win: ```java HarnessAgent.builder() .skillRepository(communityMarket) .skillRepository(internalRegistry) .skillRepository(teamGitRepo) .build(); ``` ## Workspace skills Workspace skills need no registration; just put the directory in place. ### Shared by everyone ``` workspace/skills/ └── code-reviewer/ ├── SKILL.md ├── references/ │ └── style-guide.md └── scripts/ └── run-checks.sh ``` Best for project-specific rules, internal conventions. ### Per-user To install a skill for a single user, or to override a shared one, place it under a directory named after their `userId`: ``` workspace/ ├── skills/code-reviewer/SKILL.md ← shared version └── alice/ └── skills/ └── code-reviewer/ └── SKILL.md ← visible only to Alice; overrides the shared version ``` This requires the caller to pass `userId="alice"` in `RuntimeContext`. `workspace/<userId>/skills/` is a **logical path**, not necessarily "a directory on the local disk." Skill files are read and written through the `AbstractFilesystem` abstraction, and where they physically land depends on the [filesystem mode](/v2/en/docs/harness/filesystem) you configure — so per-user skill isolation is decoupled from the storage backend: - **Local + shell** — literally `workspace/alice/skills/...` on the host disk. - **Shared store (remote filesystem)** — the `skills/` prefix is routed to the KV store; per-user isolation shows up as the namespace key `agents/<agentId>/users/alice/skills/...`, consistent across replicas, and edits from an admin console take effect on the next call. - **Sandbox (sandbox filesystem)** — the host-side user directory is hydrated into the container's `/workspace` via workspace projection at sandbox start, so the agent reads the same copy inside the sandbox. Whichever mode you run, `<userId>/skills/` overrides the shared version at the same priority. For the per-mode isolation keys, physical representation, and the role of `userId`, see [Filesystem](/v2/en/docs/harness/filesystem#how-multi-user-isolation-works). ## Conflict resolution All four sources can yield a same-named skill. Priority from low to high: | Priority | Source | How to configure | |----------|--------|------------------| | 1 (lowest) | Project-global dir | `projectGlobalSkillsDir(Path)`, e.g. `~/.agentscope/skills/` | | 2 | Marketplaces | `skillRepository(...)`; later registrations win | | 3 | Workspace shared | `workspace/skills/` | | 4 (highest) | Per-user | `<userId>/skills/` | Non-conflicting skills from lower layers still show up; they're only shadowed on name collision. Example: the team Git has a generic `code-reviewer`; the project's `workspace/skills/code-reviewer/` overrides it for this codebase; Alice's `<alice>/skills/code-reviewer/` overrides that for Alice only — other users still see the project version. ## Common builder options | Method | Notes | |--------|-------| | `skillRepository(repo)` | Append a marketplace; callable multiple times | | `skillRepositories(list)` | Replace all marketplaces at once | | `projectGlobalSkillsDir(path)` | Enable the project-global dir; skipped if missing | | `disableDynamicSkills()` | Turn off "re-merge before each call"; merge once at build | Subagents inherit the parent's marketplaces and project-global dir automatically. When to use `disableDynamicSkills()`: one-shot tasks; or slow marketplace stores you don't want to refetch per call. Usually don't touch it. ## Self-learning loop (optional) Harness stitches together a loop that lets the agent draft / curate / archive skills on its own. Each stage is independently opt-in: ### Step 1: let the agent write skills ```java HarnessAgent.builder() ... .enableSkillManageTool(SkillManageConfig.defaults()) .build(); ``` Once enabled, the agent gets two tools: - `propose_skill` — write a new skill as a draft to `skills/_drafts/<name>/`, pending review - `skill_manage` — edit existing skills (create / edit / add ancillary files / delete) Skip the "draft → review" two-step and let the agent's writes go live directly: `.enableSkillManageTool(true)` (`autoPromote=true`). Not recommended for production. The framework also auto-bumps a usage counter every time the agent calls `load_skill_through_path` / `read_skill`, kept in `skills/.usage.json` — data that powers cleanup and canary rollout below. ### Step 2: add a review gate + visibility filter ```java .enableSkillPromotionGate( new LocalApprovalGate(LocalApprovalGate.defaultPrompter()), // who reviews new CompositeFilter(List.of( // how to expose new EnvironmentFilter("prod", skillUsageStore), new CanaryFilter(0.10, skillUsageStore) ))) .environment("prod") ``` - **Gate** — drafts must pass it before being promoted to real skills. Three built-in flavors: reject-all (default), local human approval (stdin etc.), notify-and-wait. - **Visibility filter** — decides which agent-authored skills the agent can see during reasoning. Compose by deployment environment tag, canary percentage, allow-list. ### Step 3: background periodic curation ```java .enableSkillCurator(SkillCuratorConfig.builder() .intervalHours(7 * 24) // weekly .staleAfterDays(30) .archiveAfterDays(90) .build()) ``` A throttled background job runs: skills unused for 30+ days become stale; for 90+ days move into `skills/.archive/`. An optional LLM "umbrella merge" pass can also run (dry-run by default — emits reports, doesn't actually change files). ### Programmatic triggers From application code: ```java List<SkillAuditLog.Entry> entries = agent.queryAudit(LocalDate.now(), e -> true); agent.runCuratorOnce() // run a curation now (bypasses throttle) .subscribe(report -> System.out.println(report)); agent.promoteSkill("notes-taker", "alice") // manually promote a draft .subscribe(result -> System.out.println(result)); ``` ## How the agent reads and runs skills On each call, harness builds an `<available_skills>` block listing every skill currently in scope. The block is built once per call (during PreCall, seeded together with the system message) as a per-call runtime material and rendered after the conversation, so it stays visible as-is across every reasoning step of that call without shifting the system-prompt prefix — it is not rebuilt per step: ```xml <available_skills> <skill> <name>code-reviewer</name> <description>Use when the user asks for code review, style feedback, or PR audits.</description> <skill-id>code-reviewer_workspace-namespaced</skill-id> <files-root>/workspace/skills/code-reviewer</files-root> </skill> ... </available_skills> ``` Each entry carries just enough metadata for the agent to decide whether to load it. `<files-root>`, when present, is the absolute path the agent uses for shell execution (see below). The directory contains summaries, not the skill instructions. When the user names a skill or the task clearly matches its description, the agent is instructed to load `SKILL.md` using the exact `<skill-id>` before acting. It can reuse the full instructions while they remain in the conversation and load supporting files only as needed. For entries without `<files-root>`, it uses the loader rather than inventing a shell path, even if another entry has one. ### Reading SKILL.md and resources To activate a skill the agent calls a built-in tool — `load_skill_through_path`: - `load_skill_through_path(skillId, path="SKILL.md")` returns YAML frontmatter and the markdown body; a content-aware fence preserves embedded code blocks - `load_skill_through_path(skillId, path="references/style-guide.md")` returns any other file under the skill directory How the file gets fetched depends on where the skill came from: | Skill source | How `path` is resolved | |--------------|------------------------| | Project-global dir (Layer 1) | preloaded into memory at registration | | Marketplace — Git / MySQL / Nacos / classpath (Layer 2) | preloaded into memory by the backend | | `workspace/skills/` shared (Layer 3) | preloaded into memory at registration | | `<userId>/skills/` per-user (Layer 4) | SKILL.md preloaded; other files read on demand through `AbstractFilesystem` (per-user namespace + sandbox routing honored automatically) | The agent doesn't see this difference — `load_skill_through_path` always works the same way. The fallback chain is "in-memory hit → source-provided resource reader → error with an enumeration of available paths." Filesystem-backed skills that only preload `SKILL.md` can read supporting files on demand from their origin directory. A repository's own lazy reader takes precedence; the origin-directory fallback does not bypass it or grant a shell path. ### `<files-root>` and shell execution When a skill ships scripts (e.g. `scripts/run-checks.sh`), the agent needs an absolute path to invoke them via `execute`. That path comes from the `<files-root>` element on each skill entry. Resolution depends on the filesystem mode: | FS mode (shell available?) | Workspace skill `<files-root>` | Marketplace skill `<files-root>` | |----------------------------|--------------------------------|-----------------------------------| | Sandbox | `/workspace/skills/<name>` | `/workspace/.skills-cache/<source>/<name>` | | Local-with-shell | `<wsRoot>/skills/<name>` | `<wsRoot>/.skills-cache/<source>/<name>` | | Local without shell / Composite | (not rendered — no shell tool registered) | (not rendered) | `<files-root>` is a raw absolute path in the execution environment, including any spaces. The agent resolves script paths against it and quotes them for that environment's shell. Local Windows execution uses `cmd.exe`; local POSIX execution uses `sh`; Docker and Kubernetes execute in their sandbox. The host JVM's OS, paths, and installed runtimes do not describe the sandbox. Follow the loaded skill's script instructions and use an interpreter available where the command runs, rather than assuming `ls` or `python3` exists. The execution guidance appears only when at least one visible skill has `<files-root>`. ### Where marketplace files actually live
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub