A Rust CLI tool that delegates code generation to a local Ollama LLM, minimizing the work required from the manager (human or AI) running it. Latest Release binaries are available for Linux, MacOS, and Windows.
Currently has templates for Typescript, Rust, and Solidity. For other languages, you'll need to create custom templates for system prompts, and a custom manager prompt if you are running WorkSplit via a SOTA LLM.
When using AI assistants for code generation, the manager (you, or an AI like Claude/Opus orchestrating the work) pays the cost:
- Human managers: Time spent writing prompts, reading output, iterating on failures
- AI managers: Input/output tokens consumed reading context and crafting instructions
WorkSplit shifts the expensive work to a free local LLM (Ollama), so the manager only needs to architect the project and generate jobs, reducing output tokens by 50%-80% for complex workflows.
WorkSplit has overhead: job creation, validation, verification loops, and potential retries. This overhead is only cost-effective when generating significant amounts of code.
| Lines of Code Changed | Recommended Approach | Why |
|---|---|---|
| < 50 lines | Direct edit (manual or LLM) | WorkSplit overhead exceeds savings |
| 50-200 lines | Consider either | Break-even zone; complexity matters |
| 200-500 lines | WorkSplit preferred | Ollama handles bulk generation free |
| 500+ lines | WorkSplit strongly preferred | Significant cost savings |
Is the task < 50 lines of changes?
└─ Yes → Do it directly (don't use WorkSplit)
└─ No ↓
Is it a simple edit (1-2 locations, clear changes)?
└─ Yes → Do it directly (faster than job creation)
└─ No ↓
Will it generate 200+ lines of new code?
└─ Yes → Use WorkSplit (cost savings)
└─ No ↓
Is the change complex (multiple files, intricate logic)?
└─ Yes → Use WorkSplit (Ollama handles complexity)
└─ No → Do it directly
WorkSplit overhead ≈ $0.50-1.00 per job (job creation, validation, verification, potential retry)
To break even, the Ollama-generated code must offset this:
- At ~$0.001/line for direct LLM coding
- Break-even ≈ 300-500 lines of generated code
Rule of thumb: Use WorkSplit for features, use direct editing for fixes.
- Write a brief job file (once)
- Run
worksplit run - Check
worksplit statusfor pass/fail
The local LLM handles all the verbose code generation and verification internally.
┌─────────────────────────────────────────────────────────────────┐
│ MANAGER (expensive) │
│ Human developer OR AI assistant (Opus) │
│ │
│ Work required: │
│ • Write job files (brief markdown) │
│ • Run: worksplit run │
│ • Read: worksplit status (one-line per job) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ WORKSPLIT (orchestrator) │
│ │
│ Handles automatically: │
│ • Loading context files │
│ • Constructing detailed prompts │
│ • Parsing LLM output │
│ • Running verification │
│ • Retry on failure (one automatic retry) │
│ • Writing output files │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ OLLAMA (free/cheap) │
│ Local LLM (qwen3, etc.) │
│ │
│ Does the heavy lifting: │
│ • Reads full context files │
│ • Generates hundreds of lines of code │
│ • Verifies against requirements │
│ • Produces verbose output (costs nothing) │
└─────────────────────────────────────────────────────────────────┘
When WorkSplit sends a request to Ollama, it constructs the context in two parts:
1. System Message (from src/core/prompts.rs):
Short, action-oriented prompts that set model behavior. Example for create mode:
You are a fast coding agent. Execute immediately in a single pass.
RULES:
1. Read the prompt ONCE, then output code immediately
2. Do NOT reconsider, re-analyze, or second-guess
...
2. User Message (assembled from multiple sources):
[SYSTEM]
<contents of jobs/_systemprompt_create.md>
Language-specific guidelines, code style, output format
[CONTEXT]
### File: src/models/user.rs
<file contents>
### File: src/db/connection.rs
<file contents>
[INSTRUCTIONS]
<job markdown content - requirements, specifications>
Output to: src/services/user_service.rs
Mode-specific additions:
- Edit mode:
[TARGET FILES]with line numbers for surgical edits - Sequential mode:
[PREVIOUSLY GENERATED IN THIS JOB]and[REMAINING FILES] - Split mode:
[TARGET FILE TO SPLIT]and[ALREADY GENERATED IN THIS SPLIT] - Verify mode:
[GENERATED OUTPUT]with the code to verify
Key insight: The file-based system prompts (_systemprompt_*.md) should only contain:
- Language-specific code style guidelines
- Output format for that specific mode
- NO information about other modes (edit prompts shouldn't explain create format, etc.)
Every feature in WorkSplit is designed to reduce what the manager must read, write, or decide:
| Without WorkSplit | With WorkSplit |
|---|---|
| Manager writes detailed prompt with full context | Manager writes brief job file, WorkSplit loads context |
| Manager reads verbose LLM output | Manager reads "PASS" or "FAIL: reason" |
| Manager manually verifies code quality | Ollama verifies automatically |
| Manager debugs and re-prompts on failure | WorkSplit retries automatically once |
| Manager tracks which files were generated | WorkSplit tracks status in _jobstatus.json |
- Minimal job files: Just specify context files, output path, and requirements
- Automatic context loading: WorkSplit reads and formats context files for you
- Built-in verification: Ollama validates its own output before marking complete
- Automatic retry: One retry attempt on verification failure (no manager intervention)
- Concise status:
worksplit statusshows one line per job - Summary/status JSON:
worksplit status --summaryor--jsonfor quick checks - Dry run:
worksplit run --dry-runto preview what would run - Reset command:
worksplit reset <job_id>for failed/stuck jobs - Cancel command:
worksplit cancel <job_id|all>to stop running jobs - Retry command:
worksplit retry <job_id>to retry failed jobs - Dependency-aware ordering:
depends_onsupport andworksplit deps - Build verification: Optional build/test commands via
worksplit.toml - Batch processing: Run all jobs with
worksplit run, check results once at the end - Watch mode:
worksplit status --watchfor real-time progress monitoring - Preview mode:
worksplit preview <job>to see prompts before running - Lint command:
worksplit lintto check generated code for errors - Auto-fix:
worksplit fix <job>to auto-fix linter errors using LLM
Pre-built binaries for Linux, macOS, and Windows are available on the Latest Release page.
Install via crates.io:
cargo install worksplit# Clone and build
git clone https://github.com/PlasticDigits/WorkSplit
cd WorkSplit
cargo build --release
# Or install directly from path
cargo install --path .# Initialize a new project
worksplit init
# Create a job from template
worksplit new-job my_feature --template replace -o src/services/ -f my_service.rs
# Or create job files manually in the jobs/ directory
# See examples/sample_project for reference
# Run all pending jobs
worksplit run
# Check status
worksplit status -v
# Validate project structure
worksplit validateWorkSplit works with any programming language, not just Rust. The core workflow is language-agnostic:
- Job files describe what code to generate (in any language)
- Ollama generates the code
- WorkSplit writes the output files
However, you must customize the system prompts for your language:
| File | What to Customize |
|---|---|
jobs/_systemprompt_create.md |
Change Rust references to your language, update code style guidelines |
jobs/_systemprompt_verify.md |
Update syntax checking guidance, remove Rust-specific checks |
jobs/_systemprompt_edit.md |
Adjust FIND/REPLACE examples for your language |
worksplit.toml |
Add build_command and test_command for your build system |
Example for Python:
# worksplit.toml
[build]
build_command = "python -m py_compile"
test_command = "pytest"Example for TypeScript:
# worksplit.toml
[build]
build_command = "tsc --noEmit"
test_command = "npm test"Use worksplit new-job to quickly scaffold job files:
# Basic replace mode (generate new file)
worksplit new-job my_service --template replace -o src/services/ -f service.rs
# Edit mode (modify existing files)
worksplit new-job fix_bug --template edit --targets src/main.rs,src/lib.rs
# Sequential mode (multi-file generation)
worksplit new-job big_feature --template sequential -o src/
# Split mode (break large file into modules)
worksplit new-job refactor --template split --targets src/monolith.rs
# With context files
worksplit new-job impl_api --template replace -c src/types.rs,src/db.rs -o src/ -f api.rs| Template | Use Case |
|---|---|
replace |
Generate complete new files (default) |
edit |
Make surgical changes to existing files |
split |
Break a large file into smaller modules |
sequential |
Generate multiple files with accumulated context |
tdd |
Test-driven development (tests first, then implementation) |
After creating a job, edit the generated .md file to add your specific requirements.
After running worksplit init, your project will have:
your_project/
├── worksplit.toml # Configuration
└── jobs/
├── _systemprompt_create.md # Instructions for code generation
├── _systemprompt_verify.md # Instructions for verification
├── _managerinstruction.md # How to create job files (for AI assistants)
├── _jobstatus.json # Job status tracking (managed by WorkSplit)
└── example_001.md # Example job file
Job files use YAML frontmatter with markdown instructions:
---
context_files:
- src/models/user.rs
- src/db/connection.rs
output_dir: src/services/
output_file: user_service.rs
---
# Create User Service
## Requirements
- Implement UserService struct with CRUD methods
- Use the User model from context
- Handle database errors gracefully
## Methods to implement
- `new(db: DbConnection) -> Self`
- `create_user(user: NewUser) -> Result<User, ServiceError>`
- `get_user(id: i32) -> Result<Option<User>, ServiceError>`A single job can generate multiple files using the ~~~worksplit:path/to/file.ext delimiter format. This is useful when related files need to be generated together (e.g., a module and its types, or a struct and its tests).
~~~worksplit:src/models/user.rs
pub struct User {
pub id: i32,
pub name: String,
}
~~~worksplit
~~~worksplit:src/models/mod.rs
pub mod user;
pub use user::User;
~~~worksplit
- One job, one Ollama call, multiple files: All files are generated in a single LLM call
- Path after colon: The file path follows the delimiter, e.g.,
~~~worksplit:src/main.rs - Backward compatible: Using
~~~worksplitwithout a path uses the job'soutput_filesetting - Unified verification: All generated files are verified together as a cohesive unit
---
context_files:
- src/lib.rs
output_dir: src/
output_file: models/mod.rs
---
# Create User and Role Models
Create the user and role model files with proper module exports.
Files to generate:
- src/models/user.rs - User struct with fields
- src/models/role.rs - Role enum
- src/models/mod.rs - Module exportsThe LLM response can include multiple files:
~~~worksplit:src/models/user.rs
pub struct User {
pub id: i32,
pub name: String,
pub role: Role,
}
~~~worksplit
~~~worksplit:src/models/role.rs
#[derive(Debug, Clone, Copy)]
pub enum Role {
Admin,
User,
Guest,
}
~~~worksplit
~~~worksplit:src/models/mod.rs
pub mod user;
pub mod role;
pub use user::User;
pub use role::Role;
~~~worksplit
- Keep related files together: Use multi-file output for files that depend on each other
- Stay within limits: Total output across all files should stay under 900 lines
- Clear instructions: List the expected files in your job instructions
- Logical grouping: Group files that would naturally be reviewed together
For larger changes that exceed token limits, sequential mode allows generating multiple files with separate LLM calls while maintaining context:
---
context_files:
- src/lib.rs
output_dir: src/
output_file: main.rs # Default/fallback
output_files:
- src/main.rs
- src/commands/run.rs
- src/core/runner.rs
sequential: true # One Ollama call per file
---
# Feature Implementation
Generate the complete feature across multiple files.- One file per LLM call: Each file in
output_filesis generated with its own Ollama call - Accumulated context: Previously generated files in this job automatically become context for subsequent files
- Forward planning: The LLM sees which files remain to be generated, helping it design compatible interfaces
- Unified verification: After all files are generated, verification sees all files together
- Handle larger changes: Break token limits by processing files sequentially
- Maintain consistency: Previously generated files provide context for later ones
- Better interfaces: Knowing what files come next helps design compatible APIs
- Single verification: All files are verified together as a cohesive unit
Use sequential mode when:
- Total output would exceed 900 lines across all files
- Files have dependencies on each other that need to be respected
- You want the LLM to have visibility into previously generated code
- The change is too large for a single LLM call
Use standard multi-file output when:
- All files fit comfortably within a single LLM call
- Files are relatively independent
- Total output is under 900 lines
---
output_files:
- src/models/user.rs # Generated first
- src/services/user.rs # Sees user.rs as context
- src/handlers/user.rs # Sees both previous files
- src/routes/user.rs # Sees all three previous files
sequential: true
---
# User Management Feature
Generate the complete user management feature from model to routes.With this configuration:
src/models/user.rsis generated first (no accumulated context)src/services/user.rsis generated next (sees user model as context)src/handlers/user.rsis generated (sees model + service as context)src/routes/user.rsis generated last (sees all previous files as context)- Verification checks all four files together
created → pending_work → pending_verification → pass/fail
- created: Job file exists, ready to process
- pending_work: Sent to Ollama for code generation
- pending_verification: Generation complete, awaiting verification
- pass: Verification succeeded
- fail: Verification failed (see error for details)
Initialize a new WorkSplit project in the current directory.
worksplit init
worksplit init --path /path/to/projectProcess pending jobs.
# Run all pending jobs
worksplit run
# Run a specific job
worksplit run --job my_job_001
# Preview without executing
worksplit run --dry-run
# Resume stuck jobs
worksplit run --resume
# Reset a job to created status (legacy)
worksplit run --reset my_job_001
# Override settings
worksplit run --model llama3 --timeout 600Show job status summary.
worksplit status
worksplit status -v # Verbose: show each job
worksplit status --summary # Single-line summary
worksplit status --json # Machine-readable outputReset a job (or all failed jobs) to created status.
worksplit reset my_job_001
worksplit reset all
worksplit reset all --status partialShow dependency ordering for jobs that specify depends_on.
worksplit depsValidate the jobs folder structure and job files.
worksplit validateCancel a running job or all running jobs.
# Cancel a specific job
worksplit cancel my_job_001
# Cancel all running jobs
worksplit cancel allRetry a failed job from the beginning.
# Retry a specific job
worksplit retry my_job_001Preview the full prompt that would be sent to Ollama without actually running the job. This helps catch issues before expensive LLM calls.
# Preview a specific job
worksplit preview my_job_001Output includes:
- Job mode and output path
- Context files with line counts
- Target files (for edit mode)
- System prompt preview
- Job instructions
- Estimated token count and model info
When to use: Before running jobs with large context files, to verify the prompt looks correct.
Run linters on generated code to catch errors immediately after generation.
# Lint a specific job's output
worksplit lint --job my_job_001
# Lint all passed jobs' outputs
worksplit lintRequires: lint_command in worksplit.toml:
[build]
lint_command = "cargo clippy -- -D warnings" # Rust
lint_command = "npx eslint" # TypeScript
lint_command = "forge fmt --check" # SolidityWhen to use: After worksplit run completes, to catch syntax/style errors before committing.
Auto-fix common linter issues using LLM.
# Fix a specific job's output
worksplit fix my_job_001How it works:
- Runs the configured
lint_commandon the job's output file - If errors found, sends linter output + source file to LLM with
_systemprompt_fix.md - Parses and applies FIND/REPLACE blocks from LLM response
- Re-runs linter to verify fixes worked
When to use: After worksplit lint shows errors that are mechanical (unused variables, missing type exports, etc.).
Show job status summary.
worksplit status
worksplit status -v # Verbose: show each job
worksplit status --summary # Single-line summary
worksplit status --json # Machine-readable output
worksplit status --watch # Watch for changes in real-timeProcess pending jobs.
# Run all pending jobs
worksplit run
# Run a specific job
worksplit run --job my_job_001
# Preview without executing
worksplit run --dry-run
# Resume stuck jobs
worksplit run --resume
# Set per-job timeout (seconds)
worksplit run --job-timeout 300
# Override settings
worksplit run --model llama3 --timeout 600Create worksplit.toml in your project root:
[ollama]
url = "http://localhost:11434"
model = "qwen3"
timeout_seconds = 300
[limits]
max_output_lines = 900
max_context_lines = 1000
max_context_files = 2
[build]
# build_command = "cargo check"
# test_command = "cargo test"
# lint_command = "cargo clippy -- -D warnings"
# verify_build = true
# verify_tests = false
[behavior]
stream_output = true
create_output_dirs = trueCLI flags override config file values.
- Ollama: Must be running locally (or remotely with URL configured)
- Model: A capable coding model (e.g., qwen3, codellama, deepseek-coder)
- Rust: 1.70+ for building from source
The goal is to write jobs that pass on the first try with minimal manager effort. Every retry or edit costs you time/tokens.
DO: Write jobs that are unambiguous and complete
---
context_files:
- src/models/user.rs
output_dir: src/services/
output_file: user_service.rs
---
# Create UserService
Implement CRUD operations for User model.
## Required methods
- `create(user: NewUser) -> Result<User, Error>`
- `get(id: i32) -> Result<Option<User>, Error>`
- `update(id: i32, data: UpdateUser) -> Result<User, Error>`
- `delete(id: i32) -> Result<(), Error>`
## Constraints
- Use the User struct from context_files
- Return ServiceError for all error cases
- No unwrap() callsDON'T: Write vague jobs that need iteration
# Create a user service
Make it work with the user model.- Explicit over implicit: List every method signature, every constraint
- Include examples: If output format matters, show an example
- Reference context files: Tell Ollama exactly which types to use
- Specify error handling: "Use Result<T, E>" not "handle errors gracefully"
- One concern per job: Split complex features into multiple jobs
- Avoid edit drift: Prefer replace mode when FIND/REPLACE may change
If a context or target file exceeds 900 LOC, WorkSplit will fail with split-job instructions.
feature_order_component.md
Examples:
auth_001_user_model.md
auth_002_session_service.md
api_001_user_endpoints.md
Jobs run in alphabetical order. Use prefixes to control dependencies.
If a job fails, you have two options:
Option 1: Fix and retry (costs manager effort)
worksplit status -v # See the error
# Edit the job file to fix the issue
worksplit reset job_id # Reset and retryOption 2: Accept and move on (for non-critical failures)
- Sometimes verification is too strict
- If the generated code is acceptable, manually mark as complete or delete the job
# Quick check: just counts
worksplit status
# Output: 5 passed, 1 failed, 2 pending
# Summary or JSON for automation
worksplit status --summary
worksplit status --json
# Only if needed: see which failed
worksplit status -v
# Output: Lists each job with status
# Don't read generated files unless necessary
# Trust the verification unless status shows FAILIf you're an AI assistant using WorkSplit to generate code, here's how to minimize your token usage and maximize success rate.
- Read
_managerinstruction.mdonce to understand job format - Plan your batching - group tasks by file, not by feature
- Write job files using the template (don't craft verbose prompts)
- Validate first:
worksplit validate - Run all jobs:
worksplit run - Check summary only:
worksplit status --summary - Only investigate failures:
worksplit status --json
Batch by FILE, not by task. If multiple tasks modify the same file, create ONE job:
| Bad (7 jobs) | Good (4 jobs) |
|---|---|
| Task 1 → main.rs | main.rs ← Tasks 1,2,6,7 |
| Task 2 → main.rs | status.rs ← Tasks 1,2,4,7 |
| Task 4 → status.rs | run.rs ← Tasks 1,6 |
| Task 6 → main.rs | validate.rs ← Task 5 |
| Task 7 → main.rs |
New file? → Replace mode
Small change (<50 lines)? → Edit mode
Many similar patterns (>10)? → Replace mode (edit will fail)
Changing >50% of file? → Replace mode
Adding struct field? → See "Struct Field Pattern" below
Find/replace drift risk? → Replace mode
Adding a field to a struct requires updating all struct literals. This is error-prone in edit mode.
Recommended approach:
- Add field with
#[serde(default)]so YAML parsing still works - Use replace mode for test files, or
- Split into two jobs: one for struct definition, one for tests
# Quiet mode - no output, just exit code
worksplit run -q && echo "All passed" || echo "Some failed"
# Summary - single line
worksplit status --summary
# JSON - machine readable
worksplit status --json
# Skip verification for trusted jobs
# Add to job frontmatter: verify: false- Don't read generated files (Ollama verified them)
- Don't craft verbose prompts (job files are the prompts)
- Don't watch streaming output (just wait for completion)
- Don't manually retry (WorkSplit retries once automatically)
- Don't use edit mode for changes <10 lines (manual edit is faster)
- Don't use edit mode for multi-file changes (high failure rate)
- Don't retry edit mode more than twice (switch to replace or manual)
---
context_files:
- path/to/relevant/file.rs
output_dir: path/to/output/
output_file: filename.rs
verify: true # Set false for low-risk changes
---
# [Brief Title]
## Requirements
- [Requirement 1]
- [Requirement 2]
## Signatures
\`\`\`rust
fn function_name(args) -> ReturnType
\`\`\`
## Constraints
- [Constraint 1]
- [Constraint 2]
## Formatting Notes
- Uses 4-space indentation
- [Other style notes]| Type | Success Rate | Best For | Recommendation |
|---|---|---|---|
| Replace (single file) | ~95% | New files, rewrites | Preferred |
| Replace (multi-file) | ~90% | Related files, modules | Preferred |
| Split | ~90% | Breaking up large files | Preferred |
| Sequential | ~85% | Large multi-file features | Preferred |
| Edit (single location) | ~70% | One surgical change | Use with caution |
| Edit (2-5 locations) | ~50% | Small fixes | Often fails |
| Edit (5+ locations) | ~20% | Avoid entirely | Use replace mode |
| Edit (multiple files) | ~30% | Avoid entirely | Separate jobs or manual |
Edit mode guidance: For changes under 10 lines, manual editing is faster and more reliable than creating a job file. Reserve edit mode for 20-50 line changes in a single file where replace mode would regenerate too much code.
# Run tests
cargo test
# Run with verbose logging
RUST_LOG=debug worksplit run
# Check lints
cargo clippyAGPL-3.0-only