DAFT - v1.0.0
    Preparing search index...

    DAFT - v1.0.0

    DAFT - Declarative Agents, Fast & Type-safe

    CI API Docs

    A declarative framework for describing iterative AI agent workflows in TypeScript.

    📚 Full API Documentation

    git clone https://github.com/JoshuaSkootsky/daft.git && cd daft
    bun install
    echo 'ZEN_API_KEY=your_key_here' > .env
    bun run run-local examples/linear-spec.ts
    # ✅ Done in 4 iterations

    DAFT lets you describe what your data should look like; agents iterate until it does.

    DAFT is a declarative DSL for LLM workflows. You define structure; runtime handles execution.

    • Spec = Declarative DAG (what to do)
    • Tool = Imperative logic (how to do it)
    • Predicate = Stop condition (when to finish)
    {
    name: 'analyze',
    until: 'hasSummary',
    maxIter: 5,
    tools: ['llm'],
    dependsOn: ['extract']
    }

    Why DAFT?

    Narrow surface → Fast learning curve. Vocabulary: steps, until, tools, budget

    Declarative → Static analysis. Cycle detection, cost estimation, auto-mocking

    Type-safe → Build-time validation. TypeScript rejects misspelled predicates

    Upgrade path → Complex logic in tools; DSL stays honest

    Built with Bun + Redis: Fast runtime, native TypeScript, distributed execution

    budget: { maxTime: 45000, maxTokens: 4000, maxCost: 0.25 }
    

    Fail-fast when limits are hit. Zero surprise costs.

    • v1-showcase.ts - Earnings analysis (45s, $0.25)
    • v2-showcase.ts - Multi-pass code review
    • linear-spec.ts - Basic workflow
    • dag-spec.ts - Parallel execution
    • llm-spec.ts - Budget constraints
    • integration-spec.ts - Multiple tools

    Declarative workflow definition:

    import { predicates } from '../src/tools/predicates';
    import { tools } from '../src/tools';

    export default {
    initial: { text: "Hello" },
    steps: [{
    name: 'analyze',
    until: 'analyzeDone',
    maxIter: 5,
    tools: ['llm']
    }]
    };

    Determine when a step should stop iterating: hasSummary, hasKeywords, scoreCheck

    Tools contain imperative logic. Use built-in (llm, mockLLM) or create custom:

    export const myTool = defineTool({
    input: {} as { items: string[] },
    output: {} as { count: number },
    run: async ({ items }) => ({ count: items.length })
    });

    Define mock behavior inline for cost-free testing:

    initial: {
    _mock: {
    summary: { summary: 'Quick overview...' },
    keywords: { keywords: ['AI', 'data'] }
    }
    }

    When ZEN_API_KEY is set, steps use real LLM. When unset, mockLLM returns _mock data.

    Keep DSL honest—complex logic lives in tools, not spec. Create, register in src/tools/index.ts, and use:

    { name: 'count', until: 'hasField', tools: ['myTool'] }
    

    No if, for, or expressions in spec—declarative structure + imperative tools.

    Full API Docs • Examples • MIT License