sf-sdk-portfolio — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sf-sdk-portfolio (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.
npm install @spfunctions/[email protected]
export SF_API_KEY="sf_..." # required — portfolio is user-scopedFor live execution (sf.execution.place), the API key must have execution scope and BYOK Kalshi credentials must be connected (see sf-autopilot-setup).
import { SimpleFunctions } from "@spfunctions/sdk"
const sf = new SimpleFunctions({
apiKey: process.env.SF_API_KEY,
baseUrl: process.env.SF_API_URL ?? "https://simplefunctions.dev",
})// Current state snapshot
const state = await sf.portfolio.state()
console.log({
cash: state.cash,
exposure: state.exposure,
dailyPnl: state.dailyPnl,
totalPnl: state.totalPnl,
positions: state.positions,
status: state.status,
})
// Recent ticks (each is one evaluation cycle)
const ticks = await sf.portfolio.ticks.list({ limit: 10, envelope: true })
ticks.data.forEach(t => {
console.log({
at: t.at,
handoffNote: t.handoffNote?.slice(0, 80),
actions: t.actions?.length,
riskGates: t.riskGates,
})
})
// Recent trades
const trades = await sf.portfolio.trades.list({ limit: 10, envelope: true })
trades.data.forEach(t => {
console.log({
at: t.at,
ticker: t.ticker,
action: t.action,
quantity: t.quantity,
fillPrice: t.fillPrice,
pnl: t.pnl,
linkedThesisId: t.linkedThesisId,
})
})Use envelope: true to get pagination metadata (cursor, hasMore) alongside the data array.
Intents are the safe execution path — propose an order, review, then approve.
const intents = await sf.intents.list({ active: true })
console.log(intents.map(i => ({
id: i.id,
status: i.status, // "pending" | "approved" | "executed" | "canceled" | "expired"
ticker: i.marketId,
action: i.action,
quantity: i.targetQuantity,
maxPrice: i.maxPrice,
})))const intent = await sf.intents.get("intent-id")
console.log({
...intent,
riskGateChecks: intent.riskGateChecks,
proposedBy: intent.proposedBy, // "autopilot" | "user" | "<agent-id>"
note: intent.note,
})const created = await sf.intents.create({
action: "buy", // "buy" | "sell" | "cancel"
venue: "kalshi", // "kalshi" | "polymarket"
marketId: "KXFED-27APR-T3.50",
marketTitle: "Fed target rate <= 3.50",
direction: "yes", // "yes" | "no"
targetQuantity: 1,
maxPrice: 32, // limit price in cents
autoExecute: false, // KEEP false for human-in-the-loop
note: "Pre-trade check: 28/30 — proceed full size",
})
console.log(created.id, created.status)autoExecute: false keeps it in pending state until approved. The autopilot also creates intents with this flag — they're the queue you review.
// HTTP-direct (SDK wrapper may differ by version)
const approved = await fetch(`https://simplefunctions.dev/api/intent/${intentId}/approve`, {
method: "POST",
headers: { "Authorization": `Bearer ${process.env.SF_API_KEY}` },
}).then(r => r.json())
console.log(approved.status, approved.executionResult)Approval triggers the execution pipeline: risk gates check, then order to exchange.
const canceled = await sf.intents.cancel("intent-id")Works in pending state. After execution, use sf.execution.place({ action: "cancel", ... }) for exchange-level cancellation.
For unmediated execution (bypass intent queue):
const placed = await sf.execution.place({
ticker: "KXFED-27APR-T3.50",
action: "buy",
quantity: 1,
limitPrice: 32,
})
console.log(placed.orderId, placed.fillStatus)This ensures a usable runtime before creating the executable intent unless you pass runtime: { mode: "none" }.
Strongly recommended: don't use sf.execution.place directly. Use sf.intents.create({ autoExecute: false }) → review → approve. The intent path keeps the adversarial check on the record.
Before any order placement (via intent or direct execution), SimpleFunctions enforces risk gates configured in your portfolio:
max_exposure_usdmax_position_pctmax_daily_loss_usddrawdown_auto_halt_pctFailed gates return a structured error:
try {
await sf.intents.create({ /* ... */ })
} catch (e) {
if (e.code === "RISK_GATE_FAILED") {
console.log("Gate failed:", e.gate, e.reason, e.currentValue)
}
}See concepts/risk-gates for the full list and configuration via sf-autopilot-setup.
const watched = await sf.watchlists.list({ limit: 20 })
const alerts = await sf.alerts.list({ status: "active", limit: 20 })These are read-only surfaces. For mutation (create watch, register alert), use HTTP-direct or the CLI — see sf-watch-topic skill.
async function autopilotReviewCycle() {
// 1. Pull state
const state = await sf.portfolio.state()
if (state.status === "halted") {
return { action: "skip", reason: `halted: ${state.haltedReason}` }
}
// 2. Review pending intents
const pending = await sf.intents.list({ active: true })
const ready = pending.filter(i => i.status === "pending")
// 3. For each, fetch market state + decide
const decisions = await Promise.all(ready.map(async (intent) => {
const market = await sf.markets.get(intent.marketId)
// Apply local discipline — example: skip if spread > 5¢
if (market.spread > 5) {
return { intentId: intent.id, action: "cancel", reason: "spread too wide" }
}
return { intentId: intent.id, action: "approve" }
}))
// 4. Execute decisions
for (const d of decisions) {
if (d.action === "approve") {
await fetch(`https://simplefunctions.dev/api/intent/${d.intentId}/approve`, {
method: "POST",
headers: { "Authorization": `Bearer ${process.env.SF_API_KEY}` },
})
} else if (d.action === "cancel") {
await sf.intents.cancel(d.intentId)
}
}
return { processed: decisions.length, decisions }
}sf portfolio enable --venue kalshi.sf-sdk-quickstart — install + first callsf-autopilot-setup — risk gate + BYOK setupsf-portfolio-review — CLI workflow for the same readssf-pre-trade-check — adversarial check before approving an intent~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.