03. Tools, Permissions, Skills, and MCP
This chapter is where the Hadamard SDK starts to feel like a full agent system.
1. Tools vs. skills
- Tools perform direct actions: read files, edit files, search, take screenshots, or delegate tasks.
- Skills package a working style: debug methodically, verify a result, or run a reviewer-style pass.
2. Tool categories in the Hadamard SDK
The Hadamard SDK can combine several tool sources in one run:
- custom local tools created with
tool(...) - file tools from
createHadamardFileTools(...) - computer-use tools from
createHadamardComputerUseToolkit(...) - the clean
Taskdelegation tool when named agents are registered - MCP tools from local,
stdio, orstreamable_httpservers
3. Inspect the clean tool surface
The Hadamard SDK now has a dedicated tool catalog API:
const tools = await sdk.tools.listMetadata();
const catalog = await sdk.tools.getCatalog();
console.log(tools);
console.log(catalog.byCategory.file);
console.log(catalog.byCategory.computer);Each tool record includes:
namedescriptionprovidercategoryserverreadOnlymutating
Repository example:
4. Clean skills
Clean skills work directly through createAgentSdk(...).
List skills
console.log(sdk.skills.listMetadata());Run a skill directly
const result = await sdk.runSkill(
'debug',
'Explain what should be validated before the next release.',
);
console.log(result.text);Run a skill inside a session
const session = await sdk.createSession({ title: 'Skill demo' });
const result = await session.runSkill(
'remember',
'Remember that releases must wait for CI and npm pack --dry-run.',
);
console.log(result.text);Add a custom skill
const sdk = await createAgentSdk({
skills: [
skill({
name: 'release-check',
description: 'Review release readiness and summarize blockers.',
prompt: 'You are executing the /release-check skill.\\n\\nTask:\\n$ARGUMENTS',
}),
],
});5. Clean dream support
The Hadamard SDK now has a first-class dream API for durable memory consolidation:
const state = await sdk.dreamState();
console.log(state);
const session = await sdk.createSession({ title: 'Dream demo' });
const dreamResult = await session.dream({
extraContext: 'Consolidate stable release notes and workflow constraints.',
});
console.log(dreamResult.result?.text);Auto-dream:
await sdk.memory.updateSettings({ autoDreamEnabled: true });
await sdk.maybeAutoDream({
currentSessionId: session.id,
background: true,
});Repository example:
6. Clean slash-command replacements
The Hadamard SDK exposes command-style helpers:
console.log(sdk.slashCommands.listMetadata());
const contextResult = await sdk.slashCommands.run('context');
const toolsResult = await sdk.slashCommands.run('tools');Available clean replacements:
contextcompactmemorydreamtoolsskillsagents
These are backed by typed APIs:
sdk.context.overview(...)sdk.context.describe(...)sdk.context.compact(sessionId, ...)sdk.context.memoryState(...)sdk.dream.run(...)sdk.context.tools(...)sdk.context.skills()sdk.context.agents()
7. Permissions, classifier, and approver
Permission mode
const sdk = await createAgentSdk({
permissionMode: 'plan',
});Permission rules
const sdk = await createAgentSdk({
permissions: [
{ toolName: 'Write', behavior: 'deny' },
{ toolName: 'Read', behavior: 'allow' },
],
});Classifier
const sdk = await createAgentSdk({
classifier: ({ publicName }) =>
publicName === 'Write'
? { behavior: 'allow', reason: 'Safe write in the current flow.' }
: undefined,
});Approver
const sdk = await createAgentSdk({
permissions: [{ toolName: 'computer_*', behavior: 'ask' }],
approver: ({ publicName }) =>
publicName.startsWith('computer_')
? { behavior: 'allow', reason: 'Approved for this run.' }
: { behavior: 'deny', reason: 'Not approved.' },
});Session-specific permission state is persisted and restored:
await session.setPermissionContext({
mode: 'default',
permissions: [{ toolName: 'Bash', behavior: 'ask' }],
approver,
});
const restored = await sdk.resumeSession(session.id);
console.log(restored.permissionContext);Only serializable mode/rules are stored. Classifier and approver callbacks must be attached again by the current process. bypassPermissions still enforces hard safety checks; acceptEdits allows file-edit tools but not arbitrary shell commands; plan blocks mutating tools unless a higher-priority explicit rule or classifier allows them.
8. MCP
The SDK supports:
- local MCP servers
stdioMCP serversstreamable_httpMCP servers
import { createAgentSdk, stdioMcpServer } from 'actoviq-agent-sdk';
const sdk = await createAgentSdk({
mcpServers: [
stdioMcpServer({
name: 'filesystem',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '.'],
}),
],
});Lifecycle hooks
Use typedHooks in settings.json, or Settings > Hooks in the desktop app, to run a command, model-evaluated prompt, or HTTP callback during runtime lifecycle events. Supported events are SessionStart, SessionEnd, TurnStart, TurnEnd, ModelRequest, ModelResponse, PreToolUse, PostToolUse, PermissionDecision, Compact, Stop, WorktreeCreate, and WorktreeRemove.
Each hook has a unique id, an event, a handler, and optional matcher, timeoutMs, enabled, and errorPolicy fields. Matchers are regular expressions. HTTP callbacks require HTTPS except for loopback development URLs. Command handlers execute an executable plus arguments directly rather than through a shell.
{
"typedHooks": [
{
"id": "audit-bash",
"event": "PostToolUse",
"matcher": "^Bash$",
"handler": {
"type": "http",
"url": "https://example.com/hadamard-hook"
},
"timeoutMs": 5000,
"errorPolicy": "continue"
}
]
}The older hooks.PreToolUse, hooks.PostToolUse, and hooks.SessionStart shell-command format remains supported for compatibility. Prefer typedHooks for new configurations.
Repository examples:
- examples/hadamard-file-tools.ts
- examples/hadamard-computer-use.ts
- examples/hadamard-dream.ts
- examples/hadamard-skills.ts
- examples/hadamard-agent-helpers.ts
Next chapter: