Package Exports
- @stacksona/agent-tools
- @stacksona/agent-tools/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@stacksona/agent-tools) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@stacksona/agent-tools
Deterministic tools for AI agent workflows by Stacksona.
Website: https://stacksona.com
@stacksona/agent-tools is a standalone package for running deterministic utility tools from a CLI, TypeScript imports, or an MCP server. It can also produce Stacksona-compatible runtime event objects for use with the Stacksona SDK, but it does not import or require the SDK.
The package includes tools for safe calculation, schema validation, JSON path operations, table profiling and validation, URL checks, deterministic policy evaluation, portable policy strings, HMAC signatures, secret scanning, file inspection, hashing, text utilities, OCR, image annotation, basic image inspection, lightweight C2PA marker checks, action fingerprinting, HTTP request inspection, timezone-aware current time, time-window checks, and proof-wrapped outputs.
Each tool returns a structured response with:
- a result
- a deterministic explanation
- input and output hashes
- a replay-friendly proof envelope
- redacted canonical input by default
- structured errors with
messageandcode - separate audit metadata for timestamps
- bounded file and provenance scanning for chunked hashing and inspection
The goal is to move repeatable agent work out of prompts and into deterministic code paths that can be inspected, replayed, and logged.
Package
- Author: Stacksona
- Website: https://stacksona.com
- npm package:
@stacksona/agent-tools - Stacksona SDK:
@stacksona/sdk
Install
npm install -g @stacksona/agent-toolsOr run without global install:
npx @stacksona/agent-tools listRequirements
- Node.js 18+
- OCR requires a local
tesseractbinary image.color_summaryandimage.average_hashrequire local ImageMagickconvert- MCP mode requires an MCP-compatible client
Security controls for file, image, and OCR tools can be set in code or through environment variables. For library usage, prefer the explicit runtime config API:
import { configureAgentTools } from "@stacksona/agent-tools";
configureAgentTools({
profile: "prod",
allowedRoots: ["/safe/root"],
maxFileBytes: 10 * 1024 * 1024,
maxTableRows: 5000,
maxPolicyValueDepth: 48
});Environment variables are also supported for CLI and container deployments:
- Set
STACKSONA_AGENT_TOOLS_PROFILE=prodfor tighter default limits. - Set
STACKSONA_AGENT_TOOLS_ALLOWED_ROOTS=/safe/rootto restrict readable and writable paths. - Set
STACKSONA_AGENT_TOOLS_MCP_MODE=true; file tools then requireSTACKSONA_AGENT_TOOLS_ENABLE_FILE_TOOLS=true. - Set
STACKSONA_AGENT_TOOLS_DISABLE_FILE_TOOLS=trueto block all local file tools. - Optional limits:
STACKSONA_AGENT_TOOLS_MAX_FILE_BYTES,STACKSONA_AGENT_TOOLS_MAX_TABLE_BYTES,STACKSONA_AGENT_TOOLS_MAX_TABLE_ROWS,STACKSONA_AGENT_TOOLS_MAX_POLICY_STRING_BYTES,STACKSONA_AGENT_TOOLS_MAX_POLICY_VALUE_DEPTH.
Security and error shape
Tool failures return a structured error object:
{
"ok": false,
"error": {
"message": "human-readable failure reason",
"code": "TOOL_EXECUTION_FAILED"
}
}Unknown tools use code: "UNKNOWN_TOOL".
Proof envelopes keep input_hash based on the original canonical input for replay and audit integrity, while proof.canonical_input is redacted by default. Secret-like values are redacted even when they appear inside generic string fields, not only when the field name is secret or token.
For example, secret.scan accepts both text and value inputs and redacts bearer tokens, Stripe-like keys, Stacksona sg_... keys, GitHub tokens, JWTs, AWS access keys, private keys, connection strings, and environment-style secret assignments before exposing canonical input.
stacksona-agent-tools call secret.scan '{"text":"Bearer sk_test_1234567890abcdef","include_context":true}'
stacksona-agent-tools call secret.scan '{"text":"sg_1234567890abcdef","include_context":true}'The result includes fingerprints, previews, and optional redacted context. It does not return full secret values.
Repository layout
The source is split by feature so src/index.ts stays as the public entrypoint instead of a large implementation file:
src/core/ Shared types, canonicalization, envelopes, safety, versioning
src/tools/ Feature modules grouped by capability
src/tools/calculator.ts
src/tools/security.ts
src/tools/json.ts
src/tools/policy.ts
src/tools/text.ts
src/tools/workflow.ts
src/tools/action.ts
src/tools/http.ts
src/tools/time.ts
src/tools/url.ts
src/tools/table.ts
src/tools/file.ts
src/tools/image.ts
src/tools/provenance.ts
src/definitions.ts Tool definitions and schemas
src/registry.ts Tool dispatch
src/events.ts Stacksona-compatible runtime events
src/cli.ts CLI and MCP server entry
src/index.ts Public exports and bin entrypointCLI
List tools:
stacksona-agent-tools listRun a request file:
stacksona-agent-tools run examples/calculator.request.jsonCall a tool directly:
stacksona-agent-tools call calculator.evaluate '{"expression":"round_money(refund_amount(249.99, 49.99))"}'Start the MCP server:
stacksona-agent-tools mcpClaude Desktop MCP config
{
"mcpServers": {
"stacksona-agent-tools": {
"command": "stacksona-agent-tools",
"args": ["mcp"]
}
}
}Stacksona SDK-compatible event logging
The package does not depend on @stacksona/sdk. Instead, it can produce the same runtime event shape the SDK sends with emitRuntimeEvent.
Standalone event creation:
import { buildToolCallProposedEvent, buildToolCallResultEvent, runTool } from "@stacksona/agent-tools";
const proposed = buildToolCallProposedEvent({
tenant_id: "tenant_123",
session_id: "sess_123",
task_id: "refund-123",
tool: "calculator.evaluate",
input: { expression: "249.99 - 49.99" }
});
const response = await runTool("calculator.evaluate", {
expression: "249.99 - 49.99"
});
const result = buildToolCallResultEvent({
tenant_id: "tenant_123",
session_id: "sess_123",
task_id: "refund-123",
tool: "calculator.evaluate",
input: { expression: "249.99 - 49.99" },
response
});With the Stacksona SDK on npm, pass the SDK method as an optional emitter:
import { runToolWithEvents } from "@stacksona/agent-tools";
import { StacksonaClient } from "@stacksona/sdk";
const stacksona = new StacksonaClient({ baseUrl, token });
const { response } = await runToolWithEvents({
tenant_id,
session_id,
task_id: "refund-123",
tool: "calculator.evaluate",
input: { expression: "249.99 - 49.99" },
emit: (event) => stacksona.emitRuntimeEvent(event)
});That emits:
tool.call.proposed
tool.call.resultIf the tool fails, the second event becomes:
tool.call.failedTool usage is represented as task and session history. Later approval requests do not need attached event references because Stacksona can review the session event stream.
Tool categories
Calculation and security
| Tool | Purpose |
|---|---|
calculator.evaluate |
Safe arithmetic, statistics, formulas, constants, and unit conversion |
password.policy_check |
Check a password against a deterministic policy |
security.hash |
SHA-256 or SHA-512 hashing |
security.hmac |
HMAC generation |
Proof and data
| Tool | Purpose |
|---|---|
proof.create |
Create deterministic input/output hashes |
proof.verify |
Verify a proof envelope |
json.format |
Stable pretty-print JSON |
json.diff |
Deterministic JSON diff |
schema.validate |
JSON Schema subset validation |
json.path_get |
Get a nested JSON path |
json.path_set |
Set a nested JSON path on a copy |
json.path_remove |
Remove a nested JSON path on a copy |
json.path_exists |
Check whether a nested JSON path exists |
Text and output quality
| Tool | Purpose |
|---|---|
text.redact_sensitive |
Redact common sensitive patterns |
text.extract |
Extract emails, URLs, phones, hashtags |
text.slugify |
Deterministic slug generation |
output.check_constraints |
Check required sections, phrase bans, word limits |
output.find_missing_fields |
Find missing required object fields |
template.render |
Render safe {{path}} templates and report missing values |
Risk and decision support
| Tool | Purpose |
|---|---|
math.weighted_score |
Rank options with explicit weights |
math.percent_change |
Percent change calculator |
date.deadline_status |
Determine overdue/due soon status |
risk.detect_sensitive_fields |
Detect sensitive-looking keys and values |
risk.requires_approval |
Rule-based approval recommendation |
action.fingerprint |
Stable SHA-256 fingerprint for exact agent actions |
http.request_inspect |
Inspect planned HTTP requests before execution |
time.current |
Return the current time in a requested IANA timezone |
time.window_check |
Check whether an action is inside an allowed day/time window |
policy.evaluate |
Deterministic if/then policy evaluation |
policy.compile |
Compile a policy object into a portable stp1... policy string |
policy.decode |
Decode and verify a portable policy string |
policy.verify |
Verify a policy string hash, optional expected hash, and optional signature secret |
policy.sign |
Sign a policy string with HMAC-SHA256 |
policy.verify_signature |
Verify a signed policy string |
policy.explain |
Generate deterministic plain-text policy explanations |
policy.run |
Run values through a policy string and return output and trace |
secret.scan |
Pattern-based secret/token scanner |
url.inspect |
Local URL parser and safety classifier |
url.allowlist_check |
Deterministic URL allowlist check |
table.profile |
Profile CSV or row data |
table.validate |
Validate CSV or row data against rules |
Files, images, and provenance
| Tool | Purpose |
|---|---|
file.checksum |
File checksum |
file.inspect |
Size, extension, MIME guess, text/binary, SHA-256, and constraints |
image.metadata |
Read image dimensions |
image.annotate_boxes |
Draw boxes and labels by writing an annotated SVG |
image.color_summary |
Average RGB and coarse color buckets |
image.average_hash |
8x8 average hash |
ocr.extract_text |
OCR with optional word boxes |
provenance.c2pa_check |
Lightweight C2PA/content-credentials marker scan |
Agent action governance examples
Fingerprint an exact action before approval:
stacksona-agent-tools call action.fingerprint '{"action":{"type":"refund","amount":2500,"currency":"usd","customer_id":"cus_123"}}'Score an action before deciding whether to gate it:
Inspect a planned HTTP request before an agent executes it:
stacksona-agent-tools call http.request_inspect '{"method":"POST","url":"https://api.stripe.com/v1/refunds","headers":{"Authorization":"Bearer sk_live_redacted"},"body":{"charge":"ch_123","amount":2500}}'Check whether an action is inside an allowed operating window:
stacksona-agent-tools call time.current '{"timezone":"America/Chicago"}'stacksona-agent-tools call time.window_check '{"now":"2026-06-17T19:00:00-05:00","timezone":"America/Chicago","allowed_days":["mon","tue","wed","thu","fri"],"start":"09:00","end":"17:00"}'Workflow validation examples
Schema validation:
stacksona-agent-tools call schema.validate '{"schema":{"type":"object","required":["amount"],"properties":{"amount":{"type":"number","minimum":100}}},"data":{"amount":200}}'JSON path updates:
stacksona-agent-tools call json.path_set '{"value":{"customer":{"plan":"trial"}},"path":"customer.plan","set_value":"paid"}'URL safety checks:
stacksona-agent-tools call url.allowlist_check '{"url":"https://api.stripe.com/v1/refunds","allowed_hosts":["api.stripe.com"]}'Policy evaluation:
stacksona-agent-tools call policy.evaluate '{"facts":{"action":"refund","amount":250},"rules":[{"id":"refund_threshold","if":{"action":"refund","amount":{"gte":100}},"then":{"requires_approval":true,"reason":"refund_above_threshold"}}]}'Portable policy strings:
Compile a policy object into a portable string:
stacksona-agent-tools call policy.compile '{"policy":{"name":"Refund policy","version":1,"mode":"first_match","limits":{"allowed_tools":["schema.validate","calculator.evaluate"],"max_steps":10},"steps":[{"id":"validate_request","tool":"schema.validate","with":{"schema":{"type":"object","required":["action","amount"],"properties":{"action":{"type":"string"},"amount":{"type":"number","minimum":0}}},"data":"$values"},"save_as":"validation"},{"id":"calculate_amount","when":{"$validation.valid":true},"tool":"calculator.evaluate","with":{"expression":"$request.expression"},"save_as":"calculation"},{"id":"large_refund","match":{"action":"refund","amount":{"gte":100},"$calculation.value":{"gte":100}},"output":{"decision":"require_approval","reason":"refund_amount_above_threshold","calculated_amount":"$calculation.value"}}],"default_output":{"decision":"allow","reason":"no_policy_match"}}}'Explain that exact policy string in plain English:
stacksona-agent-tools call policy.explain '{"policy_string":"stp1.<base64url-policy>.<sha256_hash>"}'Sign and verify a policy string:
stacksona-agent-tools call policy.sign '{"policy_string":"stp1.<base64url-policy>.<sha256_hash>","secret":"issuer-secret"}'
stacksona-agent-tools call policy.verify_signature '{"policy_string":"stp1.<base64url-policy>.<sha256_hash>.<hmac_signature>","secret":"issuer-secret"}'Run request values through that exact policy string:
stacksona-agent-tools call policy.run '{"policy_string":"stp1.<base64url-policy>.<sha256_hash>","values":{"action":"refund","amount":200,"expression":"249.99 - 49.99"}}'The explanation result includes a stable plain-text policy summary for business users and reviewers. The run result includes the final policy output, policy hash, values hash, matched steps, and deterministic trace.
The policy string format is:
stp1.<base64url-canonical-policy-json>.<sha256_policy_hash>Base64url is only used for portability. Trust comes from canonical JSON, SHA-256 verification, and optional expected-hash verification with policy.verify.
policy.run enforces its tool allowlist at execution time. A crafted policy string cannot expand limits.allowed_tools beyond the built-in deterministic policy-runtime allowlist. policy.compile also rejects policy steps that request tools outside the configured allowlist, so invalid policies fail early while runtime still protects against hand-crafted strings.
Policy value resolution is depth-guarded with limits.max_resolution_depth and limits.max_value_depth, capped by runtime config. Deeply nested with, match, or output templates fail explicitly instead of recursing to arbitrary depth.
Table validation:
stacksona-agent-tools call table.validate '{"csv":"email,amount\na@example.com,100\nb@example.com,250","required_columns":["email","amount"],"column_rules":[{"column":"amount","type":"number","min":0}]}'Secret scanning:
stacksona-agent-tools call secret.scan '{"text":"Authorization: Bearer sk_test_1234567890abcdef","include_context":true}'Calculator capabilities
calculator.evaluate is a deterministic parser, not JavaScript eval.
It supports:
Operators: +, -, *, /, %, ^
Grouping: ( ... )
Decimals and scientific notation
Constants: pi, e
Basic functions: sqrt, abs, floor, ceil, round, min, max
Statistics: sum, average / avg, median
Bounds and percentages: clamp, percent, percentage / as_percent
Money rounding: round_money / money_round
Logs and trig: log, ln, sin, cos, tan
Unit conversion: convert(value, "from", "to") / unit(value, "from", "to")
Formula templates: refund_amount, weighted_totalExamples:
stacksona-agent-tools call calculator.evaluate '{"expression":"sum(10, 20, 30)"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"round_money(10.005)"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"percent(15, 200)"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"percentage(30, 200)"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"convert(1, "mi", "ft")"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"convert(100, "c", "f")"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"refund_amount(249.99, 49.99)"}'
stacksona-agent-tools call calculator.evaluate '{"expression":"weighted_total(9, .4, 5, .2, 7, .4)"}'Supported unit groups include length, mass, volume, time, digital data, and temperature. Temperature conversion supports Celsius, Fahrenheit, and Kelvin. Trig functions use radians.
percent(rate, base) returns a percent-of calculation, so percent(15, 200) returns 30.
percentage(part, total) returns part as a percent of total, so percentage(30, 200) returns 15.
Bounding-box annotation
This tool is deterministic because the caller supplies the box coordinates. The tool applies them exactly as requested and returns a new annotated SVG.
Example:
{
"tool": "image.annotate_boxes",
"input": {
"path": "./image.png",
"output_path": "./image.annotated.svg",
"boxes": [
{ "x": 20, "y": 18, "width": 80, "height": 42, "label": "Title", "color": "#ff3b30" },
{ "x": 120, "y": 90, "width": 64, "height": 64, "label": "Logo", "color": "#007aff" }
]
}
}OCR with boxes
stacksona-agent-tools call ocr.extract_text '{"path":"./receipt.png","include_boxes":true}'This returns extracted text and, when requested, word-level bounding boxes from Tesseract TSV output.
Example response shape
{
"ok": true,
"tool": "calculator.evaluate",
"result": {
"expression": "(12.5 * 4) + sqrt(81)",
"value": 59
},
"explanation": {
"summary": "Safely evaluated the arithmetic expression.",
"steps": [
"Tokenized the expression.",
"Parsed operators and functions with a deterministic grammar.",
"Rounded the numeric result to precision 12."
]
},
"proof": {
"proof_id": "sat_...",
"input_hash": "sha256:...",
"output_hash": "sha256:...",
"result_hash": "sha256:...",
"canonical_input": "...redacted...",
"canonical_input_redacted": true,
"replayable": true,
"deterministic": true,
"package_version": "1.0.0"
},
"audit": {
"issued_at": "2026-06-10T00:00:00.000Z",
"envelope_hash": "sha256:..."
}
}Testing
Run the included package tests:
npm testRun deterministic performance checks:
npm run benchOCR success tests automatically skip when Tesseract is not installed. The missing-binary behavior is still tested so environments without OCR support fail safely instead of crashing.
Performance notes
High-volume paths are bounded and avoid unnecessary quadratic or full-file memory behavior:
json.diffwalks JSON once and avoids repeated whole-subtreeJSON.stringifycomparisons.file.checksumhashes files in fixed-size chunks.file.inspectuses chunked reads for hashes and line counts, plus a small byte sample for binary detection.provenance.c2pa_checkscans marker strings in fixed-size chunks with overlap handling.- Table, policy, regex, and file tools have configurable input limits.
policy.runhas an explicit policy value resolution depth guard for nestedwith,match, andoutputtemplates.
Run deterministic performance benchmarks:
npm run benchThe benchmark covers large JSON diffs, table profiling, secret scanning, and policy execution.
Notes on determinism
The package separates deterministic proof data from audit metadata. Timestamps live in audit, not in the deterministic proof body. Sensitive inputs are redacted from proof.canonical_input and Stacksona-compatible event arguments by default. Raw input is still represented by input_hash.
| Scope | Replayable/deterministic status | Integrator note |
|---|---|---|
| Calculator, schema, JSON paths, JSON diff, URL checks, table validation, policy strings, policy signatures, secret scanning, risk checks, template rendering, hashing | Deterministic | Same input and same package version produce the same deterministic result. |
date.deadline_status with caller-supplied now |
Replayable | Pass now for audit and replay workflows. |
date.deadline_status without now |
Not replayable | The tool uses wall-clock time and marks proof.replayable=false. |
file.checksum, file.inspect, provenance.c2pa_check |
Deterministic for the same file bytes and config | File tools are bounded, sandboxable, and use streaming/chunked reads. |
ocr.extract_text |
Deterministic relative to local Tesseract version/configuration | Missing Tesseract is returned as a normal tool error response. |
image.color_summary, image.average_hash |
Deterministic relative to local ImageMagick convert version/configuration |
Missing ImageMagick is returned as a normal tool error response. |
image.annotate_boxes |
Deterministic | Caller supplies exact boxes; the tool applies them exactly. |
provenance.c2pa_check |
Lightweight deterministic marker scan | Not full C2PA manifest-chain validation. |
Use with Stacksona Gate
This package can run independently or alongside Stacksona Gate.
A typical Stacksona flow:
Agent uses @stacksona/agent-tools
↓
Tool returns result, explanation, hashes, and proof
↓
Agent sends the proof envelope into Stacksona Gate
↓
Reviewer approves or rejects with deterministic context attached@stacksona/agent-tools records what was run and how the result was produced.
Stacksona Gate controls whether the agent should proceed.