ADR 0018 — Canonical Haskell Module Tree

Cortex and the downstream Logos repository organize Haskell modules by canonical substrate and reasoning-library layers, not implementation-era roots such as Agent, Task, Run, Provider, Json, or Document.


On this page
  1. Status
  2. Context
  3. Decision
  4. Canonical Module Ownership
  5. Cortex.Algebra
  6. Cortex.Wire
  7. Cortex.Pulse
  8. Cortex.Capability
  9. Cortex.Artifact
  10. Logos
  11. Executor Boundary
  12. Migration Map
  13. Import Direction
  14. Cabal Exposure Policy
  15. Migration Slices
  16. Consequences
  17. Alternatives Considered
  18. Keep current roots and document them as staging
  19. Move everything in one large rename commit
  20. Preserve all old roots indefinitely as public compatibility modules
  21. Put all reasoning support under Capability
  22. Keep Document as a canonical root
  23. Open Questions
  24. Related

ADR 0018 — Canonical Haskell Module Tree

Status

Proposed - records the concrete Haskell module tree and migration policy for the final src/Cortex root refactor. ADR 0040 narrows this ADR after implementation: the current public Cortex Haskell roots are substrate roots only, and concrete reasoning/provider/report surfaces live in Logos.

Context

The current src/Cortex tree still exposes several implementation-era roots:

  • Cortex.Agent
  • Cortex.Provider
  • Cortex.Run
  • Cortex.Task
  • Cortex.Research
  • Cortex.Json
  • root Cortex.Document
  • root Cortex.Memory
  • Cortex.MemoryCompaction
  • root Cortex.Graph
  • root Cortex.Circuit
  • Cortex.Event and Cortex.Events

Some of these names describe mechanisms at the wrong architectural layer. Agent, Task, Run, and Research mostly describe model-mediated reasoning behavior, which belongs above the substrate in Logos. Provider is external authority, which belongs under Cortex.Capability. Document mixes generic artifact substrate with report/research semantics. Memory mixes cognitive context construction with durable Pulse state. Json and Text are generic support utilities rather than Cortex concepts. Graph is the law-bearing algebra, and Circuit is Wire’s compiled form.

ADR 0016 already decides the canonical public root taxonomy:

src/Cortex
|-- Algebra
|-- Wire
|-- Pulse
`-- Capability

Digimuoto/logos:src/Logos
|-- Archetypes
|-- Thought
|-- Memory
`-- Patterns

The remaining decision is how strict to make the Haskell tree and how to migrate current consumers without preserving the old roots as first-class vocabulary.

Decision

The canonical Cortex Haskell tree under src/Cortex is organized by substrate layer:

Cortex
|-- Algebra        -- law-bearing graph/relation algebra
|-- Wire           -- source language, contracts, ports, compiled circuit form
|-- Pulse          -- durable execution runtime, run state, events, persistence
`-- Capability     -- executor registration and native pure-executor capability surfaces

The canonical Logos Haskell tree under the downstream Digimuoto/logos repository’s src/Logos tree is organized by reasoning-library layer:

Logos
|-- Archetypes     -- epistemological modes and activation bundles
|-- Thought        -- one model-mediated node evaluation
|-- Memory         -- cognitive context construction
`-- Patterns       -- reusable reasoning programs

Only the Cortex roots should be treated as canonical public Cortex roots. Logos is public through the separate downstream logos package, not through a Cortex Cabal component. A root module such as Cortex.Wire or Logos may be an umbrella module for its own component. Other root-level modules are either temporary compatibility shims, test fixtures, or private implementation details that should move under the nearest canonical root.

Compatibility shims may remain only when there is a concrete migration need. A shim must be shallow: it re-exports the canonical module, contains no independent logic, and is documented in the migration table or module header as temporary. New code must import the canonical path.

Generic support code that is not a Cortex concept belongs outside the public Cortex root. JSON, text, HTTP, database, retry, observability, and durable-task support should live under Platform.* when reusable, or under a canonical Cortex.<Layer>.Internal.* module when it is layer-specific.

Canonical Module Ownership

Cortex.Algebra

Cortex.Algebra owns pure graph and relation algebra:

  • graph construction and validation
  • relation operations
  • Mokhov algebra laws
  • rewrite laws and validation helpers that do not depend on Wire syntax or Pulse runtime state

Target examples:

  • Cortex.Algebra.Graph
  • Cortex.Algebra.Graph.Mokhov
  • Cortex.Algebra.Relation

Root Cortex.Graph and Cortex.Graph.* are migration shims once the canonical modules exist.

Cortex.Wire

Cortex.Wire owns the authoring and compiled-program layer:

  • Wire syntax, parser, compiler, and reference grammar
  • contracts, ports, payload kinds, and runtime envelopes
  • executor references and compile-time executor projections
  • compiled circuit form produced from Wire
  • Wire rewrite/lowering rules that are language semantics rather than durable runtime behavior

The compiled circuit form moves under Wire because it is the executable shape of a Wire program, not a separate architectural root.

The active Wire syntax implementation is canonical Wire syntax, not a versioned Haskell namespace. Version labels may appear in reference grammar documents for spec history, but Haskell modules should expose the accepted syntax through Cortex.Wire.Syntax, Cortex.Wire.Parser, and Cortex.Wire.Compile rather than Cortex.Wire.V1.*.

Target examples:

  • Cortex.Wire.Syntax
  • Cortex.Wire.Parser
  • Cortex.Wire.Compile
  • Cortex.Wire.Contract
  • Cortex.Wire.Executor
  • Cortex.Wire.Port
  • Cortex.Wire.Value
  • Cortex.Wire.Circuit.IR
  • Cortex.Wire.Circuit.Lower

Root Cortex.Circuit and Cortex.Circuit.* are migration shims once the canonical modules exist.

Cortex.Pulse

Cortex.Pulse owns durable execution:

  • run ids, attempts, checkpoints, replay, resume, scheduler, frontier, and persistence
  • execution events and operator-visible runtime state
  • durable graph-state ownership and materialization
  • Pulse-specific memory state when it is persisted execution state

Target examples:

  • Cortex.Pulse.Run
  • Cortex.Pulse.Event
  • Cortex.Pulse.Executor.*
  • Cortex.Pulse.Persistence
  • Cortex.Pulse.Memory.* for durable run-state queries only

Cortex.Event, Cortex.Events, and the durable parts of Cortex.Run.Types move or shim into Pulse. Thought lifecycle events do not belong in Pulse unless they are generic execution events; model-mediated thought events belong in Logos.

Cortex.Pulse.Executor is the durable execution engine, not the canonical home for Wire executor identity or host executor registration. It runs already-bound StageAction values, persists state, resumes runs, retries stages, and records execution events. It should not know that an action came from @native.deep_report, @pure, or any future reasoning pattern except through generic stage metadata needed for replay and operator visibility.

Cortex.Capability

Cortex.Capability owns substrate authority surfaces:

  • executor registration records
  • native pure-executor configuration
  • authority checks that are required before a bound action can enter Pulse

Target examples:

  • Cortex.Capability.Executor
  • Cortex.Capability.Executor.Pure

Model clients, provider adapters, tool-call records, and structured-output fallback policy are not part of the Cortex public Haskell surface after ADR 0040. They live in Logos or in host bindings.

Capability does not own prompts, reasoning memory, archetype activations, or pattern-level evaluation. Those are Logos concerns that consume capabilities.

Cortex.Artifact

Cortex.Artifact is not a current public Haskell root. Artifact and provenance remain Cortex architecture concepts through Wire contracts, runtime envelopes, and Pulse provenance. The concrete report/document IR and rendering surface moved to Logos.Patterns.DeepReport.Artifact.* in ADR 0040.

A future substrate-shaped artifact API requires a separate ADR and a concrete reusable need. Until then, do not add an empty Cortex.Artifact marker root.

Logos

Logos owns the structured reasoning library above the substrate:

  • canonical archetype taxonomy and activation slots
  • one bounded model-mediated cognitive evaluation, named a thought
  • cognitive memory: retrieval, ranking, packing, compaction, source selection, and topological context construction
  • reusable reasoning patterns such as DeepReport
  • prompt families, memory presets, evaluation rules, contract-entry conventions, and Wire templates that are interpreted by substrate mechanisms

Target examples:

  • Logos.Archetypes.*
  • Logos.Thought.Frame
  • Logos.Thought.Policy
  • Logos.Thought.Host
  • Logos.Thought.ToolHost
  • Logos.Thought.ToolLoop
  • Logos.Thought.Runtime
  • Logos.Thought.StructuredOutput
  • Logos.Thought.Event
  • Logos.Memory.*
  • Logos.Patterns.DeepReport.*
  • Logos.Patterns.DeepReport.Executors for inert profiles or adapters, if a later executor-definition ADR introduces them
  • Logos.Patterns.PlanReview

Agent is not a canonical Cortex word. Pulse evaluates graph nodes as bounded stage actions; durable personas and product agents remain downstream. Logos may interpret selected stages as model-mediated thoughts. Task is likewise not a root. It either becomes thought runtime machinery or a named Logos pattern. Research and report-generation code become DeepReport or other Logos patterns when they are LLM-shaped reasoning semantics.

Executor Boundary

Executor is a boundary term used at several layers. It is not another canonical root beside the Cortex substrate roots or the downstream Logos component.

The layers own different parts of executor meaning:

ContextOwnsDoes not own
Cortex.Wire.ExecutorSource-level executor references such as @native.deep_report, lowered native evaluator ids such as pure, compile-time projections, port constraints, contract obligations, and inert purity/effect metadata needed by Wire.Host authority, Haskell application codecs, provider keys, DB access, prompts, or Pulse scheduling.
Cortex.Capability.ExecutorAuthority-bearing registration records: config decoders, native pure-executor configuration, application codecs, host interpreters, and runnable binding into substrate actions.Model provider policy, reasoning-pattern semantics, or durable scheduling.
Cortex.Pulse.ExecutorDurable execution of already-bound stage actions: scheduling, persistence, replay, resume, retry, cancellation, and execution events.Wire executor registry, source-level executor ids, application semantics, or provider/tool admission.
Logos.*Reasoning-shaped executor profiles, model/provider adapters, prompts, tool-call records, pattern templates, report artifact IR, and reusable catalog values that consumers may opt into.Host authority, provider credentials, product tools, DB loading, or artifact destinations.

This makes @native.deep_report a Wire executor reference admitted by a host binding. The reusable DeepReport pieces may live under Logos.Patterns.DeepReport.*, but the binding that grants runnable authority belongs to the consumer or to a Capability-level registration surface. Pulse only sees the resulting bound StageAction and its generic replay/runtime metadata.

CorePure follows the same split. Authors write pure output equations without @; the compiler lowers them to a host-registered native evaluator id whose config is checked through Wire-level syntax and contract/port rules, whose deterministic evaluator is admitted through the executor registration surface, and whose resulting action is run by Pulse. A pure evaluator may be provided upstream by Cortex, but it is not a special Pulse executor and it does not install new Pulse framing codecs. It operates over Wire values and closed, deterministic functions rather than downstream Haskell application types.

This ADR decides the namespace boundary: no top-level Cortex.Executor root, and no expansion of Cortex.Pulse.Executor into the generic executor registry. A separate ADR is required before Cortex introduces any of the following public semantics:

  • a concrete ExecutorSpec or executor-registration API
  • a revised WireCompileEnv shape for executor projections
  • a pure-expression language or pure evaluator registry
  • executor purity/effect/replay metadata with runtime consequences
  • standard upstream executor packs such as DeepReport executor profiles or structural primitives

ADR 0017 and ADR 0020 already set constraints for those future decisions: Wire gets compile-time projections, host binding grants authority, Pulse persists closed WireValue framing, and pure output equations lower to the native evaluator rather than introducing a third node executor kind.

Migration Map

The migration proceeds by adding canonical modules first, then converting imports, then retiring old exposed roots once no internal or known external consumer still requires them.

Current surfaceCanonical targetPolicy
Cortex.Graph, Cortex.Graph.*Cortex.Algebra.Graph.*Move implementation under Algebra; keep shallow root shims during migration.
Cortex.Circuit, Cortex.Circuit.*Cortex.Wire.Circuit.*Move compiled-form modules under Wire; keep shallow root shims during migration.
Cortex.Event, Cortex.EventsCortex.Pulse.Event or Logos.Thought.EventSplit execution events from thought lifecycle events.
Cortex.Provider.OpenRouter.*Logos.Provider.OpenRouter.*Provider adapters are Logos surfaces after ADR 0040.
Cortex.Agent.ConfigLogos.Thought.FrameModel/budget/prompt appendix are thought-frame concerns.
Cortex.Agent.PolicyLogos.Thought.PolicyTool scope and approval policy belong to thought orchestration.
Cortex.Agent.DefinitionLogos.Thought.Frame or removedAvoid durable persona semantics in Cortex.
Cortex.Task.HostLogos.Thought.HostHost for one model-mediated thought.
Cortex.Task.ToolHostLogos.Thought.ToolHostHost-side tool execution for a thought.
Cortex.Task.ToolLoopLogos.Thought.ToolLoopModel/tool loop is thought orchestration over capabilities.
Cortex.Task.RuntimeLogos.Thought.RuntimeThin thought runner and lifecycle helpers.
Cortex.Task.StructuredOutputLogos.Thought.StructuredOutputStructured-output fallback and model-output parsing are Logos concerns.
Cortex.Task.PlanLogos.Patterns.PlanReviewPlanner/reviewer shape is a reusable reasoning pattern.
Cortex.Task.GatherLogos.Patterns.DeepReport.GatherEvidence gathering is DeepReport pattern semantics.
Cortex.Task.ReportLogos.Patterns.DeepReport.LegacyReportTask initiallyDecompose after contracts and ports stabilize.
Cortex.Research.SectionLogos.Patterns.DeepReport.SectionSection schema is report-pattern semantics.
Cortex.Research.RuntimeLogos.Patterns.DeepReport.Section.RuntimeSection-output parsing belongs with the pattern.
Cortex.Run.TypesCortex.Pulse.Run and Logos.Thought.StageDurable run ids are Pulse; thought stage descriptors are Logos.
Cortex.Run.EngineLogos.Thought.Event or Logos.Thought.RuntimeCurrent event emission is thought lifecycle machinery.
Cortex.Document.IR, Metadata, HostLogos.Patterns.DeepReport.Artifact.*ADR 0040 moves the concrete report/document IR to Logos.
Cortex.Document.Report, SectionLogos.Patterns.DeepReport.*Report/research semantics are Logos pattern semantics.
Cortex.Memory.*Logos.Memory.*, Cortex.Pulse.*, Cortex.Capability.*, or internal helpersClassify per module; cognitive context moves to Logos, persistence stays substrate.
Cortex.MemoryCompactionLogos.Memory.CompactKeep root shim only if concrete consumers require it.
Cortex.Pulse.Memory.*Cortex.Pulse.Memory.* or Logos.Memory.Topological.*Durable execution state stays Pulse; context construction moves to Logos.
Cortex.Json.*Platform.Serde.Json.* or layer-internal helpersGeneric serde helpers are not Cortex roots.
Cortex.TextPlatform.Text or layer-internal helpersGeneric text helpers are not Cortex roots.
Logos.<Archetype>Logos.Archetypes.<Archetype>Archetypes live under the Archetypes catalog.
Logos.<Archetype>.CapabilityLogos.Archetypes.<Archetype>.ActivationAvoid collision with external-authority Capability.
Cortex.Logos.*Logos.*Cortex.Logos is superseded staging vocabulary and should not remain public.

Import Direction

The source tree enforces the vertical split:

  • Logos may import substrate modules.
  • Substrate modules must not import Logos.
  • Cortex.Algebra must not import Wire, Pulse, Capability, or Logos.
  • Cortex.Wire may import Algebra, but not Pulse or Logos.
  • Cortex.Pulse may import Algebra, Wire, and Capability where runtime execution requires those substrate surfaces, but not Logos.
  • Cortex.Capability may import platform support and shared substrate value types when necessary, but it must not encode reasoning-pattern semantics.
  • Platform.* must not import Cortex.*.

When a cycle appears, the type belongs in the lowest layer that can own the concept without importing its consumers. Do not solve cycles by adding a new public root.

Cabal Exposure Policy

cortex.cabal should expose canonical modules and temporary compatibility shims only. The main cortex library exposes substrate modules. The downstream logos package exposes Logos.* modules from its own repository. A compatibility shim should be removed from exposed-modules when Cortex, Logos, and known consumers have migrated.

New public modules must be added under a canonical root. New internal helpers should prefer other-modules or a .Internal subtree under the owning root.

Migration Slices

The refactor should land in small buildable slices:

  1. Add this ADR and update architecture/index links.
  2. Add canonical namespace spines and shallow compatibility shims where missing.
  3. Move provider adapters to Logos and retire Cortex provider imports.
  4. Move graph algebra to Cortex.Algebra.Graph.*.
  5. Move compiled circuit modules to Cortex.Wire.Circuit.*.
  6. Move report/document artifact IR to Logos.
  7. Move thought runtime surfaces from Agent, Task, and Run into Logos.Thought.*.
  8. Move report/research surfaces into Logos.Patterns.DeepReport.*.
  9. Classify memory modules and move cognitive-context modules to Logos.Memory.*.
  10. Move generic JSON/text helpers to Platform.* or internal helpers.
  11. Remove obsolete exposed roots once compatibility windows close.

Each slice must keep the library buildable. A moved module and its tests should land together. Generated or Cabal materialization changes must stay with the source change that requires them.

Consequences

Positive consequences:

  • The Haskell tree matches the architecture docs and ADR 0016.
  • LLM-shaped and reasoning-layer code becomes visibly separate from the runtime substrate.
  • Provider authority, tool authority, artifact substrate, and reasoning patterns get distinct homes.
  • New code has a clear import target and fewer ambiguous root names.

Costs and risks:

  • Many imports and test module names will churn.
  • Compatibility shims may temporarily make the tree look duplicated.
  • Moving memory and structured-output modules requires judgement because some functions are generic mechanics and others are reasoning policy.
  • External consumers may need coordinated migration if they import old roots.

Mitigations:

  • Keep shims shallow and temporary.
  • Move one layer at a time.
  • Add import-boundary checks once the canonical tree exists.
  • Prefer deletion of unused compatibility roots over preserving them for hypothetical consumers.

Alternatives Considered

Keep current roots and document them as staging

Rejected. The current roots encode outdated concepts and continue to invite new code into the wrong layer.

Move everything in one large rename commit

Rejected. A single tree-wide rename would be difficult to review and would make it harder to distinguish semantic boundary decisions from mechanical import updates.

Preserve all old roots indefinitely as public compatibility modules

Rejected. Indefinite shims make the old vocabulary permanent. Compatibility must be justified by concrete consumers and removed once migration is complete.

Put all reasoning support under Capability

Rejected. Capability means external authority. Prompts, thought frames, cognitive memory, archetype activations, and reasoning patterns consume authority but do not grant it.

Keep Document as a canonical root

Rejected. Document currently mixes generic artifact substrate with report and research semantics. Artifact is the substrate concept; report/research shape is Logos pattern semantics.

Open Questions

  • Which old root modules still have concrete external consumers that require temporary exposed shims?
  • Should any provider-neutral model contract ever become substrate API, or should all model/provider surfaces stay in Logos and host bindings?
  • Which Cortex.Memory.* modules are purely cognitive context construction, and which are generic enough to remain substrate/internal support?
  • Does a future Cortex.Artifact root need a generic contract catalog for artifact references, or should artifact contracts remain in Wire until schemas mature?