Skills and AgentExecution

September 12, 2026 ยท View on GitHub

A real-world Skill is a revisioned knowledge and work-procedure package. Its SKILL.md supplies guidance and its indexed resources may supply references, examples, assets, or scripts. A Skill is not an execution route, strategy engine, action grant, or workflow.

Ownership

LayerOwner
Install, parse, revision, resolve, list, pack membershipSkillLibrary
Task-scoped selector intent, exact revision binding, required/model-decision modeAgentExecution
Progressive disclosure of guidance/resourcesTaskContext + SkillContextSource + ContextReader
Model request, AgentTask, TaskDAG, workflow, side effectExisting execution owner
Released management-shaped compatibility callsAgently.skills_executor thin facade

SkillLibrary installs immutable content-addressed revisions. An execution binds the exact revision, not a mutable directory alias. Skill descriptions may be offered to a semantic model selector; local code must not route free-form task text with keyword tables or regular expressions.

Agently.skills_executor, Agently.skill_library, and agents created by the same Agently application share one canonical SkillLibrary instance. The compatibility facade reconfigures that instance in place; it does not install packs into a separate global registry. Resolve pack members through Agently.skill_library when the installation call starts from the facade, then bind the returned exact revision through the agent execution.

contract = Agently.skills_executor.install_skills(
    "./skills/release-review",
    trust_level="local",
    update=True,
)

execution = (
    agent
    .use_skills([contract["skill_id"]], mode="required")
    .input("Review release candidate 3.2.0.")
    .output({
        "decision": (str, "GO or NO-GO", True),
        "risks": ([str], "Grounded release risks", True),
    })
)
result = await execution.async_get_data()

mode="required" binds the selected revisions fail-closed. With mode="model_decision", AgentExecution asks a structured ModelRequest to select from host-issued keys, validates the result, and binds the chosen revisions. Unknown or duplicate keys fail closed.

Skills use the same composition grammar as Actions; there is no separate public collection API. agent.use_skills(..., always=True) configures the Agent defaults, while execution.use_skills(...) adds declarations for one execution. Before selection, AgentExecution resolves those declarations into an execution-scoped, revision-pinned snapshot and offers only its bounded metadata cards to the model. An execution with no Skill declarations does not scan the global SkillLibrary. Installing or changing another Skill after preparation does not silently widen the running execution.

agent.require_skills(...) is the explicit required-mode convenience method. agent.use_skills_packs(...) expands an installed immutable pack to its pinned revision refs.

Revision availability is not consumption evidence. AgentTask records a Skill context consumption only when the disclosed package is attached to a concrete ModelRequest response. That consumption is context evidence, not an executable planner capability or Action evidence.

What Agently.skills_executor still does

The facade is retained for released application calls that manage or project Skills:

  • configure the SkillLibrary root and accepted trust labels;
  • install, list, inspect, and read Skill packages;
  • install/list/inspect local Skill packs and authorized Git/local source snapshots;
  • build a compatibility context-pack projection;
  • expose the TaskDAG skill resolver helper.

That TaskDAG helper is a legacy compatibility seam, not a complete TaskDAGExecutor integration in 4.1.4.8 (unchanged from 4.1.4.7). The real executor passes TaskDAGContext while the helper consumes a mapping-shaped projection. Host code would have to adapt that boundary. Do not present direct registration as proven until the framework owns the adapter and an end-to-end executor test; reverify this limitation for later release lines.

It does not own route selection, effort strategies, stages, React loops, runtime chains, Blocks lowering, script execution, capability inference, automatic Action mounting, or approvals. A registered SkillSourceProvider may materialize an authorized remote source to an immutable local snapshot; SkillLibrary installs only that snapshot and records the exact provenance. Remote compatibility installs default to untrusted; callers must explicitly promote a reviewed immutable revision. Local installs retain their local trust default. A selected Git/local subpath is resolved without following symlink components outside the materialized source root.

pack = await Agently.skills_executor.async_build_context_pack(
    task="Prepare the release review",
    skills=[contract["skill_id"]],
    include_references=True,
)

This method creates a temporary TaskContext and uses the same ContextReader contracts as ordinary execution. The compatibility-only actionize_scripts=True flag leaves selected scripts as ordinary resource descriptors and emits skills.compat.actionize_scripts_ignored; it does not discover, generate, mount, or authorize Actions.

Each projected Skill retains action_candidates: [] for compatibility with released dictionary consumers. It stays empty regardless of that flag; script descriptors remain in selected_resources, not an Action registration list.

For normal AgentExecution work, prepare the Skill scope and explicitly enable one restricted script-exec Action for the required language. The Action accepts only a relative script_path and bounded args; the host resolves that path against the execution's frozen exact-revision bindings and records the resolved revision, path, and digest in Action evidence. Enabling the Action does not invalidate the prepared TaskContext or repeat Skill applicability selection.

from agently.types.data import SkillScriptAuthorization

await execution.async_prepare_task_context()
exec_action_id = agent.enable_skill_script_exec(
    execution,
    authorization=SkillScriptAuthorization(
        auto_allow=True,
        expected_outputs=("output/report.json",),
    ),
)
action_result = await agent.action.async_execute_action(
    exec_action_id,
    {"script_path": "scripts/check.py", "args": []},
)
artifact = next(
    item
    for item in action_result["artifacts"]
    if item["path"].endswith("output/report.json")
)
readback = await execution.task_workspace.read_file(artifact["path"])

enable_skill_script_exec(...) reuses one stable ordinary Action definition per Agent/language, then binds authorization only in the current execution's Action scope and execution context. It does not create one Action per script or user request. If the same relative path exists in more than one bound Skill, narrow the execution's Skill declarations or use the released bind_skill_script_action(...) compatibility API for an explicit exact-path binding. Do not call enable_code_runtime(...) only for a Skill script; that would expose an additional general-purpose code Action. Trust is package provenance policy, not script permission. Only the successful Action record plus TaskWorkspace readback proves the side effect and collected bytes. Published artifact paths are TaskWorkspace-relative private paths under .agently/files/.../code_execution/.../output/.

Later phases of one task versus new user requests

The candidate scope is not the set of bound Skills. The default implementation performs initial applicability selection when preparing TaskContext. Later async_read_task_context(...) calls select resources within already bound sources for their intent, consumer and phase. They do not automatically activate initially unselected Skills or rescan the global SkillLibrary.

Declare Skills known to be required for the whole task, including later phases, before starting:

execution = (
    agent.create_execution()
    .input(task)
    .require_skills([planning_skill_ref, delivery_skill_ref])
)
await execution.async_prepare_task_context()

Their root guidance is required content; optional resources remain progressively read. Require only genuinely necessary Skills. Availability does not prove model consumption or authorize scripts. On-demand activation of an unbound Skill within the same run is not a current default capability.

A later user message needs the Skill

Use a fresh AgentExecution for every user request. Session carries conversation and memory only; it does not carry the previous execution's Skill bindings, Action scope, or script authorization. Declare potentially relevant Skills as ordinary Agent defaults so each fresh execution can evaluate them against its current message:

agent.use_skills([contract["skill_id"]], always=True)

# The first message does not need a script. Its selector may choose no Skill,
# and the host enables no script Action.
first = agent.create_execution().input(first_user_message)
first_result = await first.async_get_data()

# A later message requests script-backed work, so it gets a fresh execution.
later = agent.create_execution().input(later_user_message)
await later.async_prepare_task_context()
if later.skill_bindings:  # The application still applies its allowlist/policy.
    agent.enable_skill_script_exec(
        later,
        authorization=SkillScriptAuthorization(auto_allow=True),
    )
later_result = await later.async_get_data()

A started execution and a dispatched ModelRequest are snapshots; neither can receive a hot-added Skill or Action. If prompt or Skill declarations change after authorization but before start, Agently revokes the script authorization and Action visibility that depended on the old TaskContext. Prepare and authorize again.

Released execution convenience adapter

agent.run_skills_task(...) and agent.async_run_skills_task(...) remain result-shaped adapters over one ordinary AgentExecution:

compat = await agent.async_run_skills_task(
    "Review release candidate 3.2.0.",
    skills=[contract["skill_id"]],
    mode="required",
    output={"decision": (str, "GO or NO-GO", True)},
)
print(compat.execution.id, compat.output)

The adapter does not choose a skills route. The execution uses the same model_request or explicit AgentTask strategy as any other request. New code should prefer the direct AgentExecution API when it needs streams, metadata, TaskContext diagnostics, retries, or lifecycle control.

Context limits and progressive disclosure

Installing a Skill does not copy all of its resources into every prompt. SkillContextSource contributes revision-pinned resource descriptors and exact reads to the TaskContext-owned internal ContextIndex. Required SKILL.md guidance is delivered once within a ContextPackage; its child section descriptors are not offered or delivered again when the complete root is already present. Resource indexes and explicit references allow later bounded reads. Structural, lexical, or optional hybrid indexing may narrow reusable candidates, but TaskContext remains the aggregate and SkillLibrary remains source truth. When available context is too large, the reader returns omissions and diagnostics plus refs for later reads. It never pretends that a synthetic summary is the full source.

The default resource-selection request receives instruction content already read for this read, with its completeness markers, to interpret conditional resource requirements for the current phase. Optional resource bodies stay unread until the Host validates the selected keys and reads them exactly. Without read guidance, selection continues to use the intent, phase, and candidate cards. This adds no selection node or Skill/Action permissions and does not change the custom selector call signature. If both a complete resource root and its child section are selected, package delivery deduplicates them using their source identity and declared parent relation, regardless of selection order. An incomplete root does not replace its child; reads already performed still consume their budget.

Use one or more bounded information blocks selected for the consumer and phase. Keep full files and raw evidence in SkillLibrary, TaskWorkspace, or RecordStore; put only the task-relevant package on the hot model path. Embedding/cache accounting is separate from model prompt-token accounting; cache reuse alone is not evidence that the final prompt used fewer tokens.

Side effects

Skills describe how work should be done. Host code, ActionRuntime, ExecutionResource, TaskWorkspace, RecordStore, TaskDAG, and TriggerFlow retain their existing responsibilities. A Skill cannot silently grant filesystem, network, MCP, credential, or process access.