sf-agent-sdk-quickstart — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sf-agent-sdk-quickstart (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.
Agent.create().send().stream() API with policy gatesClaude Agent SDK, Codex SDK, and Cursor SDK give agents file, shell, editor, repo, or conversation control. SimpleFunctions Agent SDK gives agents a governed view of prediction markets:
/api/contracts/toolssideEffect and costEffect metadatacanUseTool() input shrinking and denialwatch.ticks() and watch.world() inputsUse CLI or MCP when an external host owns the runtime. Use @spfunctions/agent when your TypeScript app owns the loop.
npm install @spfunctions/[email protected] @spfunctions/[email protected]
export SF_API_KEY="sf_..."
export OPENROUTER_API_KEY="sk-or-..."import { Agent } from "@spfunctions/agent/v1"
const agent = await Agent.create({
apiKey: process.env.SF_API_KEY,
openRouterApiKey: process.env.OPENROUTER_API_KEY,
model: { id: "anthropic/claude-haiku-4.5" },
})
const run = agent.send("Read world state and summarize the largest market moves.")
for await (const event of run.stream()) {
console.log(event.type)
}
// Resume from another process
const sameRun = await Agent.getRun(run.id, { agentId: run.agentId })
await sameRun?.wait()The run handle supports:
| Method | Purpose |
|---|---|
run.stream() | Async iterable of typed events |
run.wait() | Block until terminal state |
run.cancel() | Stop a running agent |
run.status | Current state (pending, running, completed, failed) |
Agent.getRun(runId, { agentId }) | Cross-process resume |
agent.send(prompt, { onDelta, onStep }) | Callbacks for streaming |
Agent.create({ apiKey }) mounts read-only strict tools by default. Write tools are opt-in only — pass builtinTools: "all" or a named allowlist.
This is the canonical "monitor + react" pattern:
import { Agent, OpenRouterProvider } from "@spfunctions/agent/v1"
const agent = await Agent.create({
apiKey: process.env.SF_API_KEY,
provider: new OpenRouterProvider({ apiKey: process.env.OPENROUTER_API_KEY }),
model: { id: "anthropic/claude-haiku-4.5" },
builtinTools: [
"world.read",
"markets.screen",
"markets.search",
"market.inspect",
"regime.scan",
"crossvenue.pairs",
],
options: {
watch: [
{ kind: "ticks", tickers: ["KXEXAMPLE"], cadence: "5min" },
],
maxTurns: 4,
maxBudgetUsd: 0.50,
canUseTool(toolName, input) {
if (toolName === "markets.search" && input && typeof input === "object") {
return { behavior: "allow", updatedInput: { ...input, limit: 5 } }
}
return { behavior: "allow" }
},
},
})
const run = agent.send([
"Watch Iran oil risk.",
"If market ticks move sharply, inspect the ticker and explain what changed.",
"Do not use write or trading tools.",
].join(" "))
for await (const event of run.stream()) {
console.log(event.type)
}Key parameters:
builtinTools: explicit allowlist of strict canonical tools (recommended over "all")options.watch: semi-realtime input streams that wake the agent on changesoptions.maxTurns: cap on agent reasoning turnsoptions.maxBudgetUsd: hard cap on LLM cost per runoptions.canUseTool: pre-tool-call gate; can deny, allow, or shrink inputFor direct streaming without LLM loop:
import { watch } from "@spfunctions/agent/v1"
for await (const tick of watch.ticks({
tickers: ["KXEXAMPLE"],
cadence: "5min",
cycles: 1,
})) {
console.log(tick.ticker, tick.price, tick.delta)
}
for await (const snap of watch.world({
cadence: "5min",
cycles: 12,
})) {
console.log(snap.asOf, snap.regime?.label)
}Use watch primitives when you want raw stream data without the LLM-driven loop.
For consumers who prefer the Anthropic-pattern query():
import { OpenRouterProvider, query, tool } from "@spfunctions/agent/v1"
const inspect = tool("market.inspect", "Inspect one market", { type: "object" }, async input => input)
for await (const message of query({
prompt: "Explain what prediction markets imply about Fed cuts.",
options: {
provider: new OpenRouterProvider({ apiKey: process.env.OPENROUTER_API_KEY }),
model: "anthropic/claude-haiku-4.5",
tools: [inspect],
maxTurns: 3,
maxBudgetUsd: 0.25,
},
})) {
console.log(message.type)
}query() yields ordered SDKMessage events. Supported runtime methods on the iterator:
interrupt()setModel(modelId)setPermissionMode(mode)setMcpServers(servers)streamInput(input)close()initializationResult()import { tool } from "@spfunctions/agent/v1"
const myTool = tool(
"thesis.summarize",
"Summarize a thesis given a thesis id",
{
type: "object",
properties: { id: { type: "string" } },
required: ["id"],
},
async ({ id }) => {
// your handler
return { summary: `Thesis ${id}: ...` }
}
)Custom tools are first-class — they appear alongside builtin tools in the agent's planning.
Live Kalshi execution requires explicit policy:
import { SimpleFunctions } from "@spfunctions/sdk"
import { SimpleFunctionsAgent } from "@spfunctions/agent"
const sf = new SimpleFunctions({ apiKey: process.env.SF_API_KEY })
const executionAgent = new SimpleFunctionsAgent({
client: sf,
policy: {
maxSideEffect: "live_trade",
maxCostEffect: "venue_request_cost",
trade: {
allowedVenues: ["kalshi"],
allowedTickers: ["KXFED-27APR-T3.50"],
maxQuantity: 2,
maxOrderCostCents: 100,
requireLimitPrice: true,
allowRuntimeStart: true,
confirmToken: "operator-approved",
},
},
})
await executionAgent.tools.execution.place({
ticker: "KXFED-27APR-T3.50",
action: "buy",
quantity: 1,
limitPrice: 32,
confirm: "operator-approved",
})The policy enforces a whitelist of venues, tickers, quantities, and costs. Execution attempts outside the policy fail-closed.
SF_API_KEY. No-key paths are limited to manifest inspection + replay-only.maxSideEffect: "none").maxBudgetUsd. Increase budget or reduce tool calls.sf-sdk-quickstart — install + first SDK callsf-agent-sdk-headless — externally-driven NDJSON harnesssf-claude-code-setup — when Claude Code owns the runtime instead~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.