zoobzio February 20, 2026 Edit this page

Architecture

This document describes the system design and architectural decisions in cogito.

Design Principles

1. Everything is Text

In LLM space, all information is fundamentally text-based. Notes store content as strings, and structured data is extracted through typed primitives like Analyze[T].

2. Append-Only Notes

Thoughts maintain an append-only log of Notes. If a key is reused, the new note becomes the current value, but history is preserved. This enables:

  • Audit trails of reasoning
  • Rollback to previous states

3. Context Accumulation

Each primitive in a pipeline reads unpublished notes, sends them to the LLM, and marks them as published. This prevents redundant context while maintaining conversation flow.

4. Two-Phase Reasoning

Primitives support optional introspection:

  1. Reasoning Phase - Deterministic (temperature 0) for consistent outputs
  2. Introspection Phase - Creative (temperature 0.7) for semantic summaries

Component Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         Application                              │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                          Pipeline                                │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │
│  │Sequence │ │ Filter  │ │ Switch  │ │Fallback │ │Concurrent│   │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘   │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                         Primitives                               │
│  ┌────────┐ ┌────────┐ ┌──────────┐ ┌──────┐ ┌──────────┐      │
│  │ Decide │ │Analyze │ │Categorize│ │Assess│ │Prioritize│      │
│  └────────┘ └────────┘ └──────────┘ └──────┘ └──────────┘      │
│  ┌──────┐ ┌────────┐ ┌────────┐                                 │
│  │ Sift │ │Discern │ │Reflect │                                 │
│  └──────┘ └────────┘ └────────┘                                 │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                          Thought                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │ Notes[] │ Session │ PublishedCount │ Intent                │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                       Infrastructure                             │
│  ┌──────────┐  ┌──────────┐                                      │
│  │ Provider │  │ Signals  │                                      │
│  │ (LLM)    │  │(Capitan) │                                      │
│  └──────────┘  └──────────┘                                      │
└─────────────────────────────────────────────────────────────────┘

Primitive Processing Flow

Each primitive follows the same pattern:

┌─────────────────────────────────────────────────────────────┐
│                    Primitive.Process()                       │
├─────────────────────────────────────────────────────────────┤
│ 1. Get unpublished notes from Thought                        │
│ 2. Render notes to context string                            │
│ 3. Resolve provider (step → context → global)               │
│ 4. Build prompt with context                                 │
│ 5. Call provider (reasoning phase, temp=0)                   │
│ 6. Parse structured response                                 │
│ 7. Store result as Note                                      │
│ 8. [Optional] Run introspection (temp=0.7)                   │
│ 9. Mark notes as published                                   │
│ 10. Emit signals                                             │
│ 11. Return modified Thought                                  │
└─────────────────────────────────────────────────────────────┘

Concurrency Model

Thoughts are safe for concurrent reads but not concurrent writes:

// Safe: Concurrent reads
go func() { thought.GetContent("key1") }()
go func() { thought.GetContent("key2") }()

// Unsafe: Concurrent writes
go func() { thought.SetContent(ctx, "key1", "v1", "src") }() // Don't do this
go func() { thought.SetContent(ctx, "key2", "v2", "src") }() // Don't do this

// Safe: Clone for parallel processing
clone1 := thought.Clone()
clone2 := thought.Clone()
go func() { process(clone1) }()
go func() { process(clone2) }()

Observability

cogito emits capitan signals throughout execution:

SignalDescription
ThoughtCreatedNew thought initialised
StepStartedPrimitive processing began
StepCompletedPrimitive processing succeeded
StepFailedPrimitive processing failed
NoteAddedNote added to thought
NotesPublishedNotes sent to LLM context

Extension Points

Custom Primitives

Implement pipz.Chainable[*Thought]:

type MyPrimitive struct {
    key string
}

func (p *MyPrimitive) Process(ctx context.Context, t *cogito.Thought) (*cogito.Thought, error) {
    // Read context
    notes := t.GetUnpublishedNotes()

    // Process with LLM
    provider, _ := cogito.ResolveProvider(ctx, nil)
    // ...

    // Store result
    t.SetContent(ctx, p.key, result, "my_primitive")
    t.MarkNotesPublished(ctx)

    return t, nil
}

func (p *MyPrimitive) Name() pipz.Name { return pipz.Name(p.key) }
func (p *MyPrimitive) Close() error    { return nil }

Performance Considerations

  1. Token Management - Use Compress/Truncate to limit context size
  2. Parallel Execution - Use Converge for independent processing paths

Next Steps