Welcome to Chapter 4!
In the previous chapter, Dynamic Prompt Construction & Budgeting, we learned how to present a "Menu" of skills to the AI without running out of memory.
Now, imagine the AI looks at that menu and orders "Delete All Files."
Just because a skill is available doesn't mean the AI should be allowed to run it immediately. We need a security system. In SkillTool, this system is the Permission & Safety Layer.
The easiest way to understand this layer is to imagine a Nightclub Bouncer.
checkPermissions function.When a guest (Skill) arrives at the door, the Bouncer follows a strict protocol:
Let's look at two scenarios:
read-file to look at code. This is harmless. We want this on the VIP List so the AI can work fast without bothering us.deploy-to-production. This is risky. We want the Bouncer to Ask the Manager before opening the door.
Here is how SkillTool makes that decision:
Let's explore the code in SkillTool.ts to see how this Bouncer logic is built.
checkPermissions)
Every tool in our system has a checkPermissions function. This is the first line of defense.
// From SkillTool.ts
async checkPermissions({ skill }, context): Promise<PermissionDecision> {
const commandName = skill.trim()
const appState = context.getAppState()
// ... logic follows ...
}
Explanation: The function receives the skill name (e.g., "deploy") and the current application state.
First, we check if the user has explicitly forbidden this skill.
// From SkillTool.ts (inside checkPermissions)
const denyRules = getRuleByContentsForTool(
permissionContext,
SkillTool as Tool,
'deny',
)
for (const [ruleContent, rule] of denyRules.entries()) {
if (ruleMatches(ruleContent)) {
return { behavior: 'deny', message: 'Blocked by rule' }
}
}
Explanation: We look up any "deny" rules created by the user. If the skill matches (e.g., the user blocked deploy:*), we return deny immediately. The AI is told "No."
If the skill isn't banned, we check if it is inherently "Safe."
In SkillTool, we don't just list safe names. We check the properties of the command.
// From SkillTool.ts
if (
commandObj?.type === 'prompt' &&
skillHasOnlySafeProperties(commandObj)
) {
return { behavior: 'allow', updatedInput: { skill, args } }
}
Explanation: If the command is a simple prompt and passes the skillHasOnlySafeProperties test, it gets VIP status (behavior: 'allow'). It runs instantly without user interaction.
What makes a command safe? We use an allowlist of properties called SAFE_SKILL_PROPERTIES.
// From SkillTool.ts
const SAFE_SKILL_PROPERTIES = new Set([
'name',
'description',
'model',
'effort',
'argNames',
// ... other harmless properties ...
])
Explanation: This list defines the "Safe Zone." Properties like name or description don't change your computer state.
Here is the logic that enforces the VIP list. It checks if the command has any "weird" or "dangerous" properties not on the list.
// From SkillTool.ts
function skillHasOnlySafeProperties(command: Command): boolean {
for (const key of Object.keys(command)) {
// If key is in the safe list, it's fine
if (SAFE_SKILL_PROPERTIES.has(key)) continue
// If it has a property NOT in the list (e.g. 'requiresNetwork'),
// it is NOT safe.
return false
}
return true
}
Explanation:
executeShellCommand: true (which is not in SAFE_SKILL_PROPERTIES), the function returns false.If the skill wasn't denied, but also isn't "Safe," we default to asking the user.
// From SkillTool.ts
return {
behavior: 'ask',
message: `Execute skill: ${commandName}`,
suggestions: [
{ type: 'addRules', behavior: 'allow', ... } // Suggest "Always Allow"
]
}
Explanation:
behavior: 'ask': This triggers a popup in the UI asking the user to Yes/No the action.suggestions: We proactively offer the user a button to "Always Allow" this skill in the future, adding it to their personal Allow Rules.The Permission & Safety Layer ensures that the "Universal Remote" we built in Chapter 1 doesn't become a dangerous weapon.
Now that we know the skill is allowed to run, what happens if the skill is incredibly complex? What if the skill needs to write code, run tests, and fix errors all by itself?
For that, we need to create a sub-agent.
Next Chapter: Forked Execution Strategy
Generated by Code IQ