Agent Skills¶
Overview¶
Agent Skills are the capability organization mechanism for PersonAgent. The problem it solves goes beyond “how to write plugins” — it addresses how to decompose behavioral mechanisms from social science into inspectable simulation stages: what a person perceives, how they interpret the situation, what intention they form, what action they take, and which experiences they carry into subsequent decisions.
Skills follow a metadata-first, selected-only model:
Selection stage: the LLM only sees the skill catalog (
name+description) and decides which skills to activate from that metadata.Execution stage: only skills selected by the LLM are loaded, read, and executed (lazy loading).
This keeps prompt size under control because unselected skills do not enter the context, while skills can evolve independently and be hot-loaded. A skill is a self-contained directory with at least one SKILL.md file (YAML frontmatter plus behavior documentation), and optionally scripts/ for executable scripts and references/ for reference material.
Note
This page describes the post-Ray-refactor skill subsystem. The old built-in observation / cognition / plan / memory skills have been removed; skill infrastructure (registry / runtime) has moved from agent/skills/ down into agentsociety2.agent.base; and skill scripts now execute by default in the agent process through entrypoint instead of forking a subprocess on every step. The only current built-in skill is Built-in Skill: daily-guidance. The most authoritative engineering notes are in the source file agentsociety2/agent/skills/README.md.
Design Goals¶
On-demand loading: Reduces unnecessary context usage and execution overhead at each step.
Interpretable selection: Selection is based on short descriptions in the catalog, facilitating debugging and review.
Hot-update friendly: supports runtime scanning, activation/deactivation, and reloading; custom skills are discovered when placed under
custom/skills/.File-convention decoupling: Skills exchange state through workspace files rather than calling each other directly.
In-process execution: scripts use
entrypointby default, reuse a warm interpreter, run in milliseconds, and are fully concurrency-safe.
Skill Directory Structure¶
Built-in skills live under agentsociety2/agent/skills/; custom skills live under workspace custom/skills/; environment-module skills are provided by the environment. SkillRegistry scans directories and uses namespace@name as the stable skill_id.
# 内置技能(命名空间 built-in)
agentsociety2/agent/skills/
└── daily-guidance/
├── SKILL.md # frontmatter(name/description/script/hooks)+ 行为说明
├── scripts/
│ └── daily_guidance.py
└── references/
# 自定义技能(命名空间 custom,热加载)
{workspace}/custom/skills/
└── my-skill/
├── SKILL.md
└── scripts/
└── my_skill.py
# 环境模块技能(命名空间 env)
{env_module}/skills/
└── weather-query/
└── SKILL.md
Scan rules: each subdirectory must contain SKILL.md or it is skipped; directories starting with . or _ are ignored; duplicate names (same skill_id) are first-wins. At agent startup, default_activated_skill_ids configures which skills are activated by default.
SKILL.md Format¶
Each skill directory must contain a SKILL.md file. The file header uses YAML frontmatter to describe metadata:
---
name: daily-guidance
description: 强制使用:凡是时间尺度在小时及以下的日常行为模拟,必须使用本 Skill ...
script: scripts/daily_guidance.py
hooks:
pre_step: scripts/daily_guidance.py
---
# Daily Guidance
(激活后被注入 system prompt 的行为说明……)
Frontmatter fields:
Field |
Description |
|---|---|
|
Display name, combined with the namespace to form |
|
Catalog description: the only text visible to the LLM during selection, and what determines whether it activates the skill. Keep it concise and actionable. |
|
Optional default script relative path, such as |
|
Optional lifecycle hook script mapping. Keys are hook types ( |
Note
The Markdown body after the frontmatter is the behavior instruction injected into the system prompt after the skill is activated. It does not enter context when inactive. When activated, it supports $ARGUMENTS / $1 / $2 placeholder substitution and !cmd command-output injection.
Visibility and Activation¶
Visible: the skill appears in the catalog, so the LLM can see it and choose to activate it.
Activated: the body of the skill’s
SKILL.mdis injected into the system prompt, and its scripts / hooks can be called.
The LLM operates on skills through these tools:
Tool |
Purpose |
|---|---|
|
Load a skill’s |
|
Remove a skill from context. |
|
Read files inside a skill for progressive disclosure. |
|
Execute a skill script. |
Before each step(), the main ReAct loop refreshes the visible skill set. In ask mode for external Q&A, only the read-only tool subset is exposed.
Script Execution Model: In-Process entrypoint¶
This is the core of the current implementation. Historically, skill scripts executed as subprocesses (python script.py <argv>), forking a new interpreter for every agent on every step, with high cold-start cost. After the redesign, skill scripts execute inside the agent process by default, with three priority levels:
① entrypoint(argv, ctx) ← 首选:缓存 import 后直接调用,毫秒级,完全并发安全
② 动态包装器(exec) ← 兜底:无 entrypoint 时,以 __name__=="__main__" 就地执行
③ 子进程(python script.py) ← 最后回退:模块无法 import 时
entrypoint Contract: Recommended for All Skill Scripts¶
A skill script can define an entrypoint at module top level; the runtime calls it first:
def entrypoint(argv: list[str], ctx) -> str:
"""进程内入口。
Args:
argv: 命令行参数(去掉脚本名之后的部分),与子进程方式的 sys.argv[1:] 一致。
ctx: SkillScriptContext,携带本 agent 的运行上下文。
Returns:
str: 脚本原本会打印到 stdout 的文本(通常是 YAML/JSON 结果块)。
"""
Key points:
Signature compatibility: the runtime detects arity, supporting both
entrypoint(argv)andentrypoint(argv, ctx). Accepting ``ctx`` is strongly recommended.Return stdout: do not rely on captured
printoutput; directlyreturnthe result string.Exceptions mean failure: if
entrypointraises, the call is recorded as failed (exit_code=1). Do not usesys.exit(); represent logical failure in the returned text, for exampleok: false.Idempotent loading: the runtime caches modules by
(path, mtime), so module top-level code executes only once.
SkillScriptContext¶
For in-process execution, context is passed explicitly through ctx (defined in agent/base/runtime.py):
Field |
Description |
|---|---|
|
Workspace root for this agent, corresponding to the old subprocess-era |
|
Skill Directory Structure |
|
Registered id ( |
|
Environment snapshot (dict) that would have been set in subprocess mode. |
Concurrency Safety Requirements (Important)¶
In one simulation, multiple agents may run their skill scripts concurrently inside the same process. The following process-level state is shared and must not be read or written directly inside entrypoint or data races can occur:
Do not |
Use instead |
|---|---|
|
|
|
|
|
|
Using mutable module-level globals as per-call state |
Use |
Dynamic Wrapper¶
Scripts without entrypoint are executed in-place by a dynamic wrapper: the source is exec-ed in a fresh namespace with __name__ == "__main__". This is semantically equivalent to a subprocess, but reuses the warm interpreter and avoids fork. Because it temporarily mutates process-level state such as os.environ, os.chdir, and stdout capture, the dynamic wrapper runs serially behind a global lock. Therefore, all hot-path scripts should provide entrypoint for full concurrency.
Built-in Skill: daily-guidance¶
The only current built-in skill is daily-guidance (built-in@daily-guidance), designed for daily behavior simulation at hourly and sub-hourly time scales. It has the agent first form a complete Story for the day (state/daily_guidance/YYYY-MM-DD/story.yaml), then uses that Story to guide behavior on each simulation step:
Submit the day plan with ``plan –json``: the script validates it and writes
story.yaml.Execution state is derived from the clock:
completed_segments/current_segment_idare functions of(segments, current simulation time)and are computed by the script when read.The ``pre_step`` hook injects the current segment on every step: it includes
activityandlocation_policy, which the agent uses for movement and questionnaire answers.It includes a needs-decay model and story revision capability for evaluating and correcting daily schedules.
Experiments such as daily-mobility activate this skill by default. It is also the reference implementation for in-process entrypoint plus pre_step hook injection (see agent/skills/daily-guidance/scripts/daily_guidance.py).
The old observation / cognition / plan / memory skills have been removed. Those cognitive and behavioral capabilities are now implemented through custom skills, workspace state files, and ask_env.
Lifecycle Hooks: pre_step / post_step¶
Declare hooks under hooks: in SKILL.md. They run automatically on every simulation step:
pre_step: runs at the start ofagent.step(), before the ReAct loop. Typical use: derive current state from the simulation clock and inject it into the first-turn context.post_step: runs after the ReAct loop. Typical use: record actual behavior and perform cleanup.
Hooks receive their payload through --args-json (including hook_type / tick / time / agent_id / step_count). After the redesign, pre_step output is rendered as a dedicated ``<skill_hooks>`` XML block in the first ReAct user message, rather than being buried in a generic observation dump that the LLM can easily ignore. For example:
<skill_hooks>
<skill_hook skill="built-in@daily-guidance" hook="pre_step" ok="true">
active_segment:
activity: sleep
location_policy: home_aoi
</skill_hooks>
This prevents the agent from spending another observation round to rediscover its state.
Environment Skills: env: Prefix¶
A skill_id starting with env: is redirected to ``ask_env`` by execute_skill_script and goes through the environment router (RouterBase) instead of executing a script. This wraps querying or operating on the simulation environment as a skill exposed to the LLM. These skills do not need entrypoint.
SkillRegistry API¶
SkillRegistry is the skill discovery center, located in agentsociety2.agent.base.skill_registry. In large-scale simulations it is a shared read-only singleton, no longer copied per agent.
Method |
Description |
|---|---|
|
Scans built-in skills (executed only once). |
|
Scan custom skills. |
|
Scans skills provided by environment modules. |
|
|
|
Look up by id / name. |
|
Read the |
|
Return skills that declare a given hook. |
|
Copy a registry, usually unnecessary. |
SkillDescriptor is the metadata for each skill: skill_id, name, description, script, hooks, source path, and so on. Activation, script execution, and hook dispatch are handled by AgentSkillRuntime; AgentBase owns its instance as self.skill_runtime.
Minimal Custom Skill Example¶
Directory:
{workspace}/custom/skills/hello-skill/
├── SKILL.md
└── scripts/
└── hello_skill.py
SKILL.md:
---
name: hello-skill
description: Add a short greeting into the step log when greeting is relevant
script: scripts/hello_skill.py
---
# Hello Skill
Write a greeting to the workspace.
scripts/hello_skill.py:
import contextvars
import json
from pathlib import Path
from typing import Any
_WORKSPACE_ROOT: contextvars.ContextVar[Path | None] = contextvars.ContextVar(
"hello_workspace_root", default=None
)
def entrypoint(argv: list[str], ctx: Any) -> str:
root = Path(str(getattr(ctx, "workspace_root"))).resolve()
_WORKSPACE_ROOT.set(root)
(root / "hello.txt").write_text("hello-skill: greeted", encoding="utf-8")
return json.dumps({"ok": True, "summary": "greeted"}, ensure_ascii=False)
if __name__ == "__main__":
# 子进程回退路径仍可用
raise SystemExit(0 if entrypoint([], type("C", (), {"workspace_root": "."})()) else 1)
Place it under custom/skills/ to hot-load it. After activation, the main LLM can choose to execute it in the right context.
Skill Authoring Checklist¶
[ ] Put the directory under
agent/skills/<name>/for built-ins or workspacecustom/skills/<name>/for custom skills.Include
SKILL.mdwith frontmatter containingname, a concise actionabledescription, and optionalscript/hooks.If a script exists, provide
def entrypoint(argv, ctx) -> strand acceptctx; get the workspace root fromctx.workspace_root; return results withreturn; usecontextvarsfor call state; share the same function between CLI dispatch andentrypoint.If declaring a
pre_stephook, make its output self-contained and directly usable as agent guidance; it will be wrapped in<skill_hooks>.[ ] Put reference material under
references/and name it explicitly inSKILL.mdso it can be read on demand.
References¶
Using Agents - PersonAgent usage guide
Architecture and Scalability - Ray execution model and
ServiceProxySkills Module - SkillRegistry API
Source
agentsociety2/agent/skills/README.md- the authoritative skill subsystem notesReAct: Synergizing Reasoning and Acting in Language Models, Yao et al. (2022): https://arxiv.org/abs/2210.03629