bx-ai-tools — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited bx-ai-tools (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
aiTool() BIF// Signature
aiTool( name, description, handler, params={} )name — unique tool identifier (snake_case recommended)description — what the tool does (clear, imperative language)handler — lambda/closure called when AI invokes the toolparams — additional parameter schema hints// Simple tool — single parameter
weatherTool = aiTool(
"get_weather",
"Get the current weather for a given location",
location -> getWeatherData( location )
)
// Multi-parameter tool — use parameter descriptions
searchTool = aiTool(
"search_database",
"Search the products database by keyword and category",
( keyword, category ) -> {
return queryExecute(
"SELECT * FROM products WHERE name LIKE :kw AND category = :cat",
{ kw: "%#keyword#%", cat: category }
)
}
)Use fluent describe*() methods to tell the AI what each parameter means:
// The method name is describe + TitleCase(parameterName)
weatherTool = aiTool(
"get_weather",
"Get current weather for a location",
location -> getWeatherAPI( location )
).describeLocation( "City and country, e.g. 'Boston, MA' or 'Paris, France'" )
searchTool = aiTool(
"search_products",
"Search the product catalog",
( keyword, category, maxResults ) -> {
return productService.search( keyword, category, maxResults )
}
)
.describeKeyword( "Search keyword or product name" )
.describeCategory( "Product category: electronics, clothing, food, or all" )
.describeMaxResults( "Maximum number of results (1-50)" )aiChat()tools = [
aiTool( "get_time", "Get current server time", () -> now() ),
aiTool( "get_uptime", "Get server uptime in hours", () -> getServerUptime() ),
aiTool( "calc", "Evaluate a math expression", expr -> evaluate( expr ) )
.describeExpr( "Math expression as a string, e.g. '(15 * 3) + 7'" )
]
result = aiChat(
"What time is it and what is 15% of 320?",
{},
{ tools: tools }
)// Prefer passing tools to aiAgent() for reusable agents
agent = aiAgent(
name : "SystemAgent",
instructions: "Use the provided tools to answer system questions accurately",
tools : [
aiTool( "get_users", "List all users", () -> entityLoad( "User" ) ),
aiTool( "get_stats", "Get system stats", () -> getSystemStats() ),
aiTool( "send_email", "Send an email",
( to, subject, body ) -> mailService.send( to, subject, body ) )
.describeTo( "Recipient email address" )
.describeSubject( "Email subject line" )
.describeBody( "Email body in plain text or HTML" )
]
)aiToolRegistry() — Shared Tool Collections// Build a reusable tool registry
registry = aiToolRegistry()
.register( aiTool( "weather", "Get weather", loc -> getWeather( loc ) ) )
.register( aiTool( "stocks", "Get stock price", sym -> getStock( sym ) ) )
.register( aiTool( "currency", "Convert currency",
( amount, from, to ) -> convertCurrency( amount, from, to ) ) )
// Share across multiple agents
agentA = aiAgent( name: "A", tools: registry.getTools() )
agentB = aiAgent( name: "B", tools: registry.getTools() )aiGlobalSkills() — Application-Wide Skills// Register skills available to ALL agents in the application
aiGlobalSkills([
aiSkill( ".agents/skills/company-guidelines/SKILL.md" ),
aiSkill( ".agents/skills/brand-tone/SKILL.md" )
])get_weather, search_products, send_email// Good error handling in a tool
dbTool = aiTool(
"query_user",
"Look up a user by ID",
userId -> {
try {
var user = entityLoadByPK( "User", userId )
return isNull( user ) ? { found: false } : { found: true, data: user.getMemento() }
} catch ( any e ) {
return { error: true, message: e.message }
}
}
).describeUserId( "Numeric user ID" )arguments scope inside tool closures — use bare parameter nameslocation -> getWeather( arguments.location )location -> getWeather( location )~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.