Agentic Trading
Decisions

ADR-0005: Skills are authored via a form, not as code

  • Status: accepted
  • Date: 2026-05-27
  • Refined by: ADR-0009 — the systemPrompt field referenced below has since been replaced with structured strategy: { entry, exit, riskManagement } fields. The form-first decision stands; the shape of one field changed.
  • Refined by: ADR-0019 — the authoring surface moved from a 7-tab form to a chat agent that writes the same SkillPayload. The "Skill is data, validated by zod" core of this ADR is preserved; only the input UX changed.

Context

A Skill is a structured configuration: model id, system prompt, whitelisted tools, risk caps, schedule, context settings. Two authoring patterns are possible:

  1. Code-first — Skill is a TypeScript file in a repo (or in a sandboxed editor); user writes export default defineSkill({...})
  2. Form-first — Skill is a database row, edited via a structured web form with field-level validation

The target audience (quants, traders) skews toward strategy intuition + market knowledge, not toward production TypeScript. Friction in iteration cycle = fewer experiments = worse strategies.

We also need every Skill to be guaranteed-valid (zod-conforming), because the same Skill is consumed by sim, live runner, and chat agent — a syntactically broken Skill would crash all three.

Decision

Skills are authored via a structured web form. Submitted Skills are validated with zod and stored as a jsonb row in skill_versions. There is no code authoring path in MVP.

A future optional "deterministic helpers" hook (Phase 4) will let advanced users add entry.ts / exit.ts helpers that the agent loop can call — but the Skill core remains form-defined.

Alternatives considered

Alt A — Code-first Skill files

  • Maximum flexibility
  • Higher iteration friction for quants
  • Requires a code editor surface, syntax errors, lint integration
  • Not picked: our users will be writing the strategy in the prompt; that's the high-leverage activity. Everything else is config — config wants a form.

Alt B — DSL (custom strategy language)

  • Power-user delight
  • Years of investment to do well
  • Not picked: we'd be building a programming language instead of a product.

Alt C — Hybrid (form for config, code for prompt)

  • The prompt textarea in the form IS the "code"
  • This is essentially what we're doing — calling it "form" because everything around the prompt is structured fields
  • (Picked, framed differently)

Consequences

Positive

  • Iteration speed: quant changes a risk cap, hits Save, runs Backtest — no build, no deploy, no syntax errors
  • Guaranteed valid: form validation + zod = every saved Skill is structurally correct
  • Versioning is automatic: every Save creates a new skill_versions row; full audit trail
  • No code execution surface to secure — Skills are pure data
  • Marketplace-ready: Skills are content-addressable JSON blobs; trivially shareable / forkable

Negative / trade-offs

  • Users can't express logic that isn't expressible as "prompt + tool calls + risk caps"
  • Adding new Skill capabilities requires a schema migration + form update + runtime update — not just docs
  • Power users may find the form constraining; they'll ask for code escape hatches (anticipated; Phase 4 addresses)

Things we'll need to revisit

  • When users demand deterministic helpers (e.g., "always exit if 7-day high broken"), introduce optional entry.ts / exit.ts hooks. Keep the agent loop in charge; helpers are advisory.
  • If we add an SDK or CLI for power users to manage Skills programmatically, it should still produce the same JSON payload — the form and the SDK both target the canonical schema.

References

On this page