Documentation Index
Fetch the complete documentation index at: https://docs.simplefunctions.dev/llms.txt
Use this file to discover all available pages before exploring further.
This guide starts from a blank TypeScript project and ends with:
- SDK install
- strict manifest inspection
- API-keyed
world.read
- Cursor-style
Agent.create().send().stream()
- semi-realtime
watch
- trace/replay for deterministic harnesses
- optional governed execution with runtime and policy guardrails
1. Install
npm init -y
npm install @spfunctions/sdk@1.0.0 @spfunctions/agent@1.0.0
Use Node 18 or newer.
2. Set Keys
For SDK data calls and Agent live execution:
export SF_API_KEY="sf_..."
For model-backed Agent runs:
export OPENROUTER_API_KEY="..."
Do not put long-lived keys in browser bundles. Use these packages from server-side TypeScript, background jobs, local agent harnesses, or trusted notebooks.
3. Inspect The Strict Contract Without A Key
/api/contracts/tools is the SDK and Agent contract truth.
import { SimpleFunctions } from "@spfunctions/sdk"
const sf = new SimpleFunctions({
baseUrl: "https://simplefunctions.dev",
})
const manifest = await sf.manifest.list()
const world = await sf.manifest.get("world.read")
const legacy = await sf.manifest.get("get_world_state")
console.log(manifest.schemaVersion)
console.log(world?.name)
console.log(legacy)
Expected:
0.3.0-draft
world.read
null
get_world_state is a broad compatibility name, not a canonical SDK/Agent tool.
4. Make The First SDK Data Call
import { SimpleFunctions } from "@spfunctions/sdk"
const sf = new SimpleFunctions({
baseUrl: "https://simplefunctions.dev",
apiKey: process.env.SF_API_KEY,
})
const world = await sf.world.get()
console.log(world.asOf)
console.log(world.regime?.label)
console.log(world.salient?.slice(0, 3).map(item => item.label))
If no API key is configured, this call throws MissingApiKeyError because world.read is cost-bearing and not anonymously allowlisted.
5. Create A Cursor-style Agent
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)
}
const sameRun = await Agent.getRun(run.id, { agentId: run.agentId })
await sameRun?.wait()
Agent.create({ apiKey }) mounts read-only SimpleFunctions strict tools by default. Write tools are opt-in only.
6. Build A Market Watch Agent
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,
maxTokens: 1024,
}),
model: { id: "anthropic/claude-haiku-4.5" },
builtinTools: ["world.read", "markets.search", "market.inspect", "market.candles"],
options: {
watch: [
{ kind: "ticks", tickers: ["KXEXAMPLE"], cadence: "5min" },
],
maxTurns: 4,
maxBudgetUsd: 0.50,
maxOutputTokens: 768,
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)
}
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)
}
8. Use Query Directly
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: "Summarize 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,
maxOutputTokens: 768,
},
})) {
console.log(message.type)
}
The low-level direct runner is still useful for deterministic harnesses:
import { SimpleFunctions } from "@spfunctions/sdk"
import { FileTraceStore, ReplayMissError, SimpleFunctionsAgent } from "@spfunctions/agent"
const sf = new SimpleFunctions({
baseUrl: "https://simplefunctions.dev",
apiKey: process.env.SF_API_KEY,
})
const trace = new FileTraceStore("./sf-agent.trace.jsonl")
const direct = new SimpleFunctionsAgent({
client: sf,
policy: { maxSideEffect: "none", maxCostEffect: "api_cost" },
trace,
})
await direct.tools.world.read({})
const replay = new SimpleFunctionsAgent({
client: new SimpleFunctions({ baseUrl: "https://simplefunctions.dev" }),
mode: "replayOnly",
trace: new FileTraceStore("./sf-agent.trace.jsonl"),
})
try {
await replay.tools.world.delta({ since: "1h" })
} catch (error) {
if (error instanceof ReplayMissError) {
console.log("Replay miss. No live call was made.")
}
}
10. Optional Governed Execution
Execution tools are not mounted by default in model-backed agents and are denied by default in the low-level direct runner unless policy explicitly allows live_trade.
import { SimpleFunctions } from "@spfunctions/sdk"
import { SimpleFunctionsAgent } from "@spfunctions/agent"
const sf = new SimpleFunctions({
baseUrl: "https://simplefunctions.dev",
apiKey: process.env.SF_API_KEY,
})
await sf.execution.place({
ticker: "KXFED-27APR-T3.50",
action: "buy",
quantity: 1,
limitPrice: 32,
runtime: { startIfNeeded: true },
})
await sf.execution.place({
venue: "polymarket",
tokenId: "POLYMARKET_CLOB_TOKEN_ID",
action: "buy",
quantity: 1,
limitPrice: 32,
runtime: { startIfNeeded: true },
})
const executionAgent = new SimpleFunctionsAgent({
client: sf,
policy: {
maxSideEffect: "live_trade",
maxCostEffect: "venue_request_cost",
trade: {
allowedVenues: ["kalshi"],
maxQuantity: 1,
maxOrderCostCents: 50,
requireLimitPrice: true,
allowRuntimeStart: true,
},
},
})
Polymarket support is runtime-backed and requires a CLOB token id, a limit price, and user-controlled runtime credentials. Applications can add blockedJurisdictions and requireJurisdiction to their Agent policy when they need venue-specific compliance safety valves.
11. Remember The Boundaries
| Surface | Scope |
|---|
@spfunctions/sdk | Typed data and contract client |
@spfunctions/agent | Cursor-style market-intelligence Agent SDK |
| Low-level direct runner | Deterministic canonical tool calls, trace, replay |
sf agent --tool | CLI wrapper for direct tool semantics |
/api/contracts/tools | Strict canonical SDK/Agent truth |
/api/tools | Broad hosted compatibility inventory |
| MCP | Broad client adapter, not SDK truth |
The packages do not expose every CLI command, every API route, or every MCP tool. They expose the strict governed subset first.