trellis/vcs

Version control model — operations, branches, milestones, checkpoints, issues, diff, merge, and blob storage.

Overview

The trellis/vcs subpath exposes the operation types and domain-level building blocks for version control. Use it when you want Trellis VCS capabilities without the full platform surface.

import { BranchEntity, MilestoneEntity, VcsOp, VcsOpKind } from "trellis/vcs";

VcsOp

Every change is an immutable, content-addressed operation:

interface VcsOp {
  hash: string; // 'trellis:op:<sha256>' — content address
  kind: VcsOpKind; // Operation type
  timestamp: string; // ISO 8601
  agentId: string; // Author identity (DID)
  previousHash?: string; // Causal chain link
  payload: Record<string, unknown>; // Kind-specific data
  signature?: string; // Ed25519 signature (when signing enabled)
}

Local durability and concurrent writers

When multiple Trellis processes write to the same repository path, the local VCS storage layer uses file locks to avoid dropped operations and duplicate issue IDs.

  • ops.json appends are lock-guarded and re-read from disk before write.
  • Writes use a temporary file plus atomic rename to avoid partial writes.
  • Replayed duplicate op hashes are ignored as an idempotency guard.
  • Issue IDs (TRL-<n>) are allocated under a lock so concurrent issue create calls stay monotonic.

If Trellis cannot acquire a local lock within a short timeout, the command fails with a lock-timeout error instead of risking log corruption.

Operation Tiers

TierOperationsDescription
1dirAdd, dirDelete, branchCreate, milestoneCreate, …Structural VCS control ops
2fileAdd, fileModify, fileDelete, fileRenameFile lifecycle ops
3astPatchSemantic AST-level patches
4Signatures, governanceCryptographic layer

Branch Entities

Branches are graph entities with a pointer to their current head op:

interface BranchEntity {
  id: string; // 'branch:<name>'
  name: string;
  headHash: string; // Current tip op hash
  createdAt: string;
  policy?: BranchPolicy;
}
// List branches
const branches = await engine.listBranches();

// Create a branch
await engine.createBranch("feature/auth");

// Switch branch
await engine.switchBranch("feature/auth");

// Delete a branch
await engine.deleteBranch("feature/old");

Milestone Entities

Milestones are human-curated markers over a range of ops:

interface MilestoneEntity {
  id: string; // 'milestone:<hash>'
  message: string;
  fromOpHash: string;
  toOpHash: string;
  affectedFiles: string[];
  authorId: string;
  createdAt: string;
}
// Create a milestone
await engine.createMilestone({
  message: "Add user authentication",
  // fromOpHash defaults to last milestone's toOpHash + 1
  // toOpHash defaults to current HEAD
});

// List milestones
const milestones = await engine.listMilestones();

Diff & Merge

File-level Diff

import { diff } from "trellis/vcs";

const result = diff(fromOpHash, toOpHash, { engine });
// { file: string; added: number; removed: number; hunks: DiffHunk[] }[]

Semantic Diff

import { semanticDiff } from "trellis/vcs";

const patches = semanticDiff(oldSource, newSource, "auth.ts");
// SemanticPatch[] — symbolAdd | symbolRemove | symbolModify | symbolRename | …

Three-way Merge

import { merge } from "trellis/vcs";

const result = await merge("feature/auth", { engine, dryRun: false });
result.conflicts; // MergeConflict[] — entity-level, with suggestions
result.clean; // true if no conflicts

Checkpoints

Auto-generated stable-state markers (created automatically when op count crosses a threshold):

interface CheckpointEntity {
  id: string;
  opHash: string; // Op at checkpoint time
  snapshotId: string; // SQLite snapshot reference
  createdAt: string;
}

Issue Tracking

Issues are first-class VCS entities, not an external system:

import { IssueEntity, IssueStatus } from "trellis/vcs";

interface IssueEntity {
  id: string; // 'issue:TRL-<n>'
  title: string;
  description?: string;
  status: IssueStatus; // 'backlog' | 'queued' | 'in_progress' | 'done' | 'closed'
  assignee?: string;
  labels: string[];
  acceptanceCriteria: string[];
  branchId?: string; // Auto-created branch when started
  createdAt: string;
  updatedAt: string;
}

See the Issue Tracking guide for the full lifecycle.

Blob Storage

Large file content is stored in the blob store and referenced by hash — keeping the op log lean:

import { BlobStore } from "trellis/vcs";

const store = new BlobStore({ dbPath: ".trellis/blobs.db" });
const hash = await store.put(Buffer.from(fileContent));
const content = await store.get(hash);