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.jsonappends 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 concurrentissue createcalls 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
| Tier | Operations | Description |
|---|---|---|
| 1 | dirAdd, dirDelete, branchCreate, milestoneCreate, … | Structural VCS control ops |
| 2 | fileAdd, fileModify, fileDelete, fileRename | File lifecycle ops |
| 3 | astPatch | Semantic AST-level patches |
| 4 | Signatures, governance | Cryptographic 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);