Read and write .cortex/ directory files — the filesystem interface for Cortex Protocol.

CortexIO

CortexIO is the filesystem interface for reading and writing .cortex/ directory files. It handles the protocol envelope (header + checksum) transparently. All protocol classes (DNAManager, Timeline, SwarmProtocol) use CortexIO internally.

import { CortexIO } from '@codmir/cortex';

Constructor

new CortexIO(projectRoot: string)
ParameterTypeDescription
projectRootstringAbsolute path to the project root. The .cortex/ directory is created inside this.
const io = new CortexIO('/home/dev/my-project');
// io.dir === '/home/dev/my-project/.cortex'

Properties

PropertyTypeDescription
dirstringAbsolute path to the .cortex/ directory

Lifecycle

init()

Creates the .cortex/ directory and the reasoning/ subdirectory if they do not exist.

async init(): Promise<void>
const io = new CortexIO('/home/dev/my-project');
await io.init();

exists()

Checks whether the .cortex/ directory exists.

async exists(): Promise<boolean>
if (await io.exists()) {
  const dna = await io.readDNA();
}

Read Methods

All read methods return a CortexFile<T> containing both the header and data, or null if the file does not exist or is unreadable.

readDNA()

Reads manifest.crtx containing the ProjectDNA.

async readDNA(): Promise<CortexFile<ProjectDNA> | null>
const file = await io.readDNA();
if (file) {
  console.log(file.header.updated);
  console.log(file.data.project.name);
}

readTimeline()

Reads timeline.crtx containing all timeline entries.

async readTimeline(): Promise<CortexFile<TimelineEntry[]> | null>

readGraph()

Reads graph.crtx containing the semantic graph.

async readGraph(): Promise<CortexFile<SemanticGraph> | null>

readSwarm()

Reads swarm.crtx containing the active swarm manifest.

async readSwarm(): Promise<CortexFile<SwarmManifest> | null>

readReasoning()

Reads a per-task reasoning file from reasoning/<taskId>.crtx.

async readReasoning(taskId: string): Promise<CortexFile<TimelineEntry[]> | null>
ParameterTypeDescription
taskIdstringTask identifier (used as filename)

listReasoningFiles()

Lists all task IDs that have reasoning files.

async listReasoningFiles(): Promise<string[]>

Returns task IDs (filenames without the .crtx extension).

const taskIds = await io.listReasoningFiles();
// ['task_abc', 'task_def', 'task_ghi']

Write Methods

All write methods create the protocol envelope automatically, including version, type, project ID, timestamps, and checksum.

writeDNA()

Writes manifest.crtx with the given ProjectDNA.

async writeDNA(dna: ProjectDNA): Promise<void>

writeTimeline()

Writes timeline.crtx with the given entries. Reads the current DNA to set the project ID in the header.

async writeTimeline(entries: TimelineEntry[]): Promise<void>

appendTimeline()

Appends a single entry to timeline.crtx. Reads the existing file, adds the entry, and writes it back.

async appendTimeline(entry: TimelineEntry): Promise<void>

writeGraph()

Writes graph.crtx with the given semantic graph.

async writeGraph(graph: SemanticGraph): Promise<void>

writeSwarm()

Writes swarm.crtx with the given swarm manifest.

async writeSwarm(manifest: SwarmManifest): Promise<void>

writeReasoning()

Writes a per-task reasoning file to reasoning/<taskId>.crtx.

async writeReasoning(taskId: string, entries: TimelineEntry[]): Promise<void>

appendReasoning()

Appends a single entry to a per-task reasoning file.

async appendReasoning(taskId: string, entry: TimelineEntry): Promise<void>

clearSwarm()

Deletes swarm.crtx.

async clearSwarm(): Promise<void>

Example

import { CortexIO } from '@codmir/cortex';
import type { ProjectDNA, TimelineEntry } from '@codmir/cortex';

const io = new CortexIO('/home/dev/my-project');

// Initialize the directory
await io.init();

// Write project DNA
const dna: ProjectDNA = {
  version: 1,
  project: {
    id: 'proj_001',
    name: 'My App',
    purpose: 'A Next.js SaaS application',
    created: Date.now(),
    updated: Date.now(),
  },
  stack: {
    languages: ['TypeScript'],
    frameworks: ['Next.js', 'React'],
    databases: ['PostgreSQL'],
    infrastructure: ['Vercel', 'AWS'],
    aiProviders: ['Anthropic'],
    buildTools: ['turbo', 'tsup'],
  },
  architecture: {
    type: 'monorepo',
    entryPoints: ['apps/web/src/app/layout.tsx'],
    boundaries: [],
    dataFlow: [],
  },
  constraints: [],
  patterns: [],
  risks: [],
  owner: { style: 'pragmatic', preferences: ['TypeScript', 'Tailwind'] },
};

await io.writeDNA(dna);

// Read it back
const file = await io.readDNA();
console.log(file?.data.project.name); // 'My App'
console.log(file?.header.checksum);   // '1a2b3c'

// Append a timeline entry
const entry: TimelineEntry = {
  id: 'entry_1',
  timestamp: Date.now(),
  agentId: 'agent_alpha',
  type: 'decision',
  action: 'Chose PostgreSQL over MySQL',
  reasoning: 'Better JSON support and Prisma compatibility',
  confidence: 0.95,
  context: { files: ['prisma/schema.prisma'], state: {} },
  refs: [],
  outcome: 'success',
};

await io.appendTimeline(entry);

// List reasoning files
const tasks = await io.listReasoningFiles();
console.log(tasks); // []