Perplexity added “Skills” to its Agent API, letting developers compose built-in and custom skills for more complex agent outputs. More skills mean more actions, and more actions mean more ways to produce an irreversible change. Before you add a fifth skill to your agent, make sure the first four have an undo path.
The undo problem
An agent skill that writes, sends, publishes, or deploys is an irreversible action if there is no rollback. The more skills an agent has, the more irreversible actions it can take in a single session. A chain of skills (research → draft → format → publish) can complete before a human notices the first step was wrong.
The undo contract
Every agent skill should declare:
{
"skill_name": "publish_to_blog",
"action_type": "write",
"reversible": true,
"undo_method": "set_published_false",
"undo_timeout_seconds": 3600,
"undo_side_effects": ["SEO index will retain the URL for up to 24h"]
}
Enter fullscreen mode Exit fullscreen mode
If reversible is false, the skill should require explicit human approval before execution.
A skill registry with undo support
# skill_registry.py
"""
Registers agent skills with undo metadata.
Blocks irreversible skills from running without explicit approval.
"""
from dataclasses import dataclass
from typing import Optional, Callable
import json
@dataclass
class Skill:
name: str
action_type: str # "read", "write", "send", "deploy"
reversible: bool
undo_fn: Optional[Callable] = None
undo_timeout_seconds: int = 3600
side_effects: str = ""
requires_approval: bool = False
class SkillRegistry:
def __init__(self):
self.skills = {}
self.execution_log = []
def register(self, skill: Skill):
# Irreversible write/send/deploy skills require approval
if not skill.reversible and skill.action_type in ("write", "send", "deploy"):
skill.requires_approval = True
self.skills[skill.name] = skill
def execute(self, skill_name: str, inputs: dict, approved: bool = False):
skill = self.skills.get(skill_name)
if not skill:
raise ValueError(f"Unknown skill: {skill_name}")
if skill.requires_approval and not approved:
return {
"status": "blocked",
"reason": "Skill is irreversible and requires explicit approval",
"skill": skill_name,
"action_type": skill.action_type
}
# Execute the skill (simulated)
result = {"status": "executed", "skill": skill_name, "inputs": inputs}
self.execution_log.append({
"skill": skill_name,
"inputs": inputs,
"result": result,
"undo_available": skill.reversible,
"executed_at": "2026-07-20T15:00:00Z"
})
return result
def undo(self, execution_index: int):
entry = self.execution_log[execution_index]
skill = self.skills[entry["skill"]]
if not skill.undo_fn:
return {
"status": "failed",
"reason": "No undo function registered",
"skill": entry["skill"]
}
undo_result = skill.undo_fn(entry["inputs"])
entry["undone"] = True
entry["undo_result"] = undo_result
return {"status": "undone", "skill": entry["skill"], "result": undo_result}
# Example usage
if __name__ == "__main__":
registry = SkillRegistry()
# Reversible skill
def undo_publish(inputs):
return f"Set published=false for {inputs.get('post_id')}"
registry.register(Skill(
name="publish_post",
action_type="write",
reversible=True,
undo_fn=undo_publish,
side_effects="SEO index retains URL for 24h"
))
# Irreversible skill
registry.register(Skill(
name="send_email",
action_type="send",
reversible=False,
undo_fn=None,
side_effects="Email cannot be un-sent"
))
# Test reversible skill
result1 = registry.execute("publish_post", {"post_id": "123", "title": "Test"})
print(f"Publish: {result1}")
# Undo it
undo1 = registry.undo(0)
print(f"Undo publish: {undo1}")
# Test irreversible skill without approval
result2 = registry.execute("send_email", {"to": "[email protected]"})
print(f"Send without approval: {result2}")
assert result2["status"] == "blocked"
# Test with approval
result3 = registry.execute("send_email", {"to": "[email protected]"}, approved=True)
print(f"Send with approval: {result3}")
assert result3["status"] == "executed"
# Try to undo (should fail)
undo2 = registry.undo(1)
print(f"Undo send: {undo2}")
assert undo2["status"] == "failed"
print("\nPASS: undo contract enforced")
Enter fullscreen mode Exit fullscreen mode
What the registry enforces
Skill type Execution Undo Read-only Always allowed Not needed Reversible write Always allowed Available within timeout Irreversible write Blocked without approval Not availableWhat to check
List every skill your agent currently has. For each one, fill in the undo contract above. If you have a skill where reversible is false and requires_approval is not enforced, you have an irreversible action running without a safety gate.
답글 남기기