Ownership
Ownership is orchex's core safety mechanism. Every stream declares which files it owns (can write) and which it reads (can only read). This prevents parallel agents from overwriting each other's work.
The Problem
Without ownership enforcement, parallel AI agents create race conditions:
Stream A: Writes src/config.ts → { port: 3000, database: "postgres" }
Stream B: Writes src/config.ts → { port: 3000, auth: { secret: "abc" } }
(runs in parallel)The last stream to finish wins. The other stream's changes are silently lost. This is the fundamental challenge of parallel code generation — and the reason most orchestration tools run tasks serially.
How Ownership Works
Declaration
Each stream declares files in two arrays:
"auth-middleware": {
owns: ["src/middleware/auth.ts"], // Can create, modify, delete
reads: ["src/types/user.ts"], // Can read, cannot modify
deps: ["user-types"],
plan: "..."
}Enforcement Points
Ownership is enforced at four points:
At
inittime — orchex validates that no two streams own the same file. If there's a conflict, the initialization fails with a clear error message.During context building — Each stream's context prompt includes only files it owns (with "you may edit") and files it reads (with "read-only — do not modify").
During artifact application — When the LLM produces file operations, orchex checks each operation against the stream's ownership list. Writes to unowned files are blocked.
During verification — After applying the artifact, orchex checks for ownership violations before marking the stream as complete.
Owns vs Reads
`owns` — Exclusive Write Access
- The stream can create, modify, or delete these files
- Only one stream can own a given file across the entire orchestration
- The LLM agent sees these files with full content and line numbers
- Attempted ownership conflicts are caught at
inittime
`reads` — Shared Read Access
- The stream can see these files in its context
- Multiple streams can read the same file simultaneously
- The LLM agent sees these files marked as "read-only"
- Useful for types, configurations, and shared interfaces
Example
streams: {
"user-types": {
owns: ["src/types/user.ts"],
plan: "Define User, UserRole, and CreateUserRequest interfaces"
},
"user-api": {
owns: ["src/routes/users.ts"],
reads: ["src/types/user.ts"], // Reads types, can't modify
deps: ["user-types"],
plan: "Create REST API routes for user CRUD operations"
},
"user-tests": {
owns: ["tests/users.test.ts"],
reads: ["src/routes/users.ts", "src/types/user.ts"], // Reads both
deps: ["user-api"],
plan: "Write integration tests for the user API endpoints"
}
}In this setup:
src/types/user.tsis owned byuser-typesand read by two other streams- Each route and test file is owned by exactly one stream
- No two streams can write to the same file
Conflict Detection
At Init Time
Error: Ownership conflict — file "src/config.ts" is owned by both
"setup-config" and "update-config". Each file can only be owned by one stream.
Suggestion: Merge these streams, or split src/config.ts into separate
files (e.g., src/config/database.ts and src/config/auth.ts).During Artifact Application
If an LLM agent attempts to modify a file it doesn't own (despite instructions not to), the operation is silently skipped and logged:
[WARN] Stream "auth-api" attempted to modify "src/types/user.ts"
which is owned by "user-types". Operation blocked.Patterns
Single Responsibility
Each stream owns files related to one concern:
"database-models": {
owns: ["src/models/user.ts", "src/models/post.ts"],
plan: "Create Prisma models for User and Post"
}Shared Types
A dedicated types stream creates interfaces that other streams read:
"api-types": {
owns: ["src/types/api.ts"],
plan: "Define Request/Response interfaces for all API endpoints"
},
"api-routes": {
owns: ["src/routes/api.ts"],
reads: ["src/types/api.ts"],
deps: ["api-types"],
plan: "Implement API routes using the defined interfaces"
}Code and Tests Together
Keep implementation and test files in the same stream when they must match:
"auth-service": {
owns: ["src/services/auth.ts", "tests/auth.test.ts"],
reads: ["src/types/auth.ts"],
plan: "Implement auth service and write vitest tests",
verify: ["npx vitest run tests/auth.test.ts"]
}This ensures the tests match the implementation without an extra dependency hop.
Migration Files
Database migrations should be isolated in their own streams:
"migration-users": {
owns: ["migrations/001-create-users.sql"],
plan: "Create SQL migration for the users table",
verify: ["npm run migrate:dry-run"]
}Automatic Ownership Inference
When you use orchex learn to parse a plan document, ownership is inferred from file references in the plan:
Create: src/routes/api.ts→ Added toownsModify: src/routes/api.ts→ Added toownsRead: src/types/api.ts→ Added toreadsImport: import { User } from '../types/user'→ Added toreads
The learn pipeline also detects ownership conflicts and generates dependency edges when one stream reads a file owned by another stream.
Pitfalls
Over-Owning
Owning too many files in one stream increases context size and reduces parallelism:
// Bad: One stream owns everything
"all-routes": {
owns: ["src/routes/users.ts", "src/routes/posts.ts", "src/routes/auth.ts",
"src/routes/billing.ts", "src/routes/admin.ts"],
plan: "Implement all API routes"
}Split into focused streams for better parallelism and manageable context.
Forgetting Reads
If a stream imports from a file it doesn't declare in reads, the LLM won't see that file's content and may generate incorrect code:
// Bad: Missing reads declaration
"api-routes": {
owns: ["src/routes/api.ts"],
// Forgot: reads: ["src/types/api.ts"]
plan: "Implement routes using ApiRequest and ApiResponse types"
}The LLM will guess at the type definitions instead of seeing the actual code.
Cross-Stream Edits
If you need two streams to modify the same file, restructure:
- Split the file — Put each stream's content in separate files
- Create a merge stream — A third stream that combines the outputs
- Reassign ownership — Give one stream ownership and make the other depend on it
Related
- Streams — Stream definition and lifecycle
- Waves — How ownership enables safe parallel execution
- Self-Healing — How ownership violations are handled
- orchex learn — Automatic ownership inference from plans