CLI Reference
Complete reference for plowman command-line interface.
Overview
plowman provides a single command plm with two subcommands:
sow: Deploy dotfiles from granaries to your home directoryharvest: Collect changes from your home directory back to granaries
Command Structure
plm [GLOBAL_OPTIONS] <SUBCOMMAND> [SUBCOMMAND_OPTIONS]
Global Options
These options apply to all commands:
-V, --version
Print version information and exit.
$ plm --version
plowman 0.3.1
-h, --help
Show help message and exit.
$ plm --help
usage: plm [-h] [-V] {sow,harvest} ...
Dotfile farm manager
positional arguments:
{sow,harvest}
sow Deploy dotfiles
harvest Collect changes back to granaries
options:
-h, --help show this help message and exit
-V, --version print the version and exit
Subcommands
sow
Deploy dotfiles from configured granaries to your home directory.
Synopsis
plm sow [OPTIONS]
Description
The sow command reads your configuration from ~/.config/plowman/config.yaml, processes all configured granaries, and deploys files to your home directory. It:
- Renders Jinja2 templates with configured variables
- Tracks deployed files in estate files
- Skips unchanged files using SHA256 hashing
- Removes orphaned files no longer in configuration
- Shows colored diffs in verbose mode
Options
-v, --verbose
Increase verbosity level. Can be stacked multiple times.
Level 0 (default): Minimal output, only errors shown
$ plm sow
(no output if no changes)
Level 1 (-v): Show which files are being copied
$ plm sow -v
☑️ Copying /home/user/dotfiles/bash/.bashrc to /home/user/.bashrc
☑️ Copying /home/user/dotfiles/git/.gitconfig to /home/user/.gitconfig
Level 2 (-vv): Show file diffs during copy
$ plm sow -vv
☑️ Copying /home/user/dotfiles/bash/.bashrc to /home/user/.bashrc
@@ -1,5 +1,5 @@
# My bash configuration
# Aliases
-alias ll='ls -l'
+alias ll='ls -la'
alias gs='git status'
Level 3+ (-vvv): Maximum verbosity with full tracebacks on errors
$ plm sow -vvv
☑️ Copying /home/user/dotfiles/bash/.bashrc to /home/user/.bashrc
@@ -1,5 +1,5 @@
# My bash configuration
...
When verbosity is enabled, Python tracebacks will show full stack traces for debugging.
-n, --dry-run
Perform a trial run without making any changes to the filesystem.
$ plm sow --dry-run
☑️ Would copy /home/user/dotfiles/bash/.bashrc to /home/user/.bashrc
☑️ Would copy /home/user/dotfiles/git/.gitconfig to /home/user/.gitconfig
🧹 Would delete /home/user/.old_config
Useful for:
- Previewing changes before applying them
- Testing new configurations
- Verifying cleanup of orphaned files
- Understanding what will be affected
Can be combined with verbose flags:
$ plm sow --dry-run -vv
☑️ Would copy /home/user/dotfiles/bash/.bashrc to /home/user/.bashrc
@@ -1,5 +1,5 @@
# My bash configuration
-alias ll='ls -l'
+alias ll='ls -la'
-h, --help
Show help for the sow command.
$ plm sow --help
usage: plm sow [-h] [-v] [-n]
options:
-h, --help show this help message and exit
-v, --verbose increase the level of verbosity
-n, --dry-run perform a trial run with no changes made
Output Format
Success Messages
Files being copied:
☑️ Copying /source/path to /destination/path
Files that would be copied (dry-run):
☑️ Would copy /source/path to /destination/path
Files being deleted (orphaned):
🧹 Deleting /path/to/orphaned/file
Files that would be deleted (dry-run):
🧹 Would delete /path/to/orphaned/file
Diff Output
Diffs use unified diff format with color coding:
- Cyan: Hunk headers (
@@ -1,5 +1,5 @@) - Yellow/Bold: File paths (
--- old,+++ new) - Green: Added lines (
+new content) - Red: Removed lines (
-old content) - Default: Context lines (unchanged)
Example:
@@ -1,5 +1,5 @@
# My bash configuration
# Aliases
-alias ll='ls -l'
+alias ll='ls -la'
alias gs='git status'
Error Messages
Errors are printed to stderr with red coloring when available.
Exit Codes
- 0: Success - operation completed successfully
- 1: Error - operation failed (see error message for details)
Common error scenarios:
- Missing configuration file
- Missing granary directory
- Template rendering errors
- Permission denied
Environment Variables
plowman does not currently use any environment variables for configuration. All settings are controlled via configuration files and command-line flags.
Configuration Files
While not command-line options, these files affect plowman's behavior:
Main Config
- Location:
~/.config/plowman/config.yaml - Purpose: Defines granaries, paths, and variables
- Required: Yes
Per-Path Config
- Location:
{path}/.plowman/plowman.yml - Purpose: Specifies which files are templates
- Required: No (optional)
Estate File
- Location:
{path}/.plowman/estate.yml - Purpose: Tracks deployed files for cleanup
- Required: Auto-generated (don't edit manually)
Examples
Basic deployment
$ plm sow
Preview changes
$ plm sow --dry-run
Verbose deployment
$ plm sow -v
Verbose with diffs
$ plm sow -vv
Maximum verbosity for debugging
$ plm sow -vvv
Dry-run with verbose output
$ plm sow --dry-run -vv
Check version
$ plm --version
plowman 0.3.1
Get help
$ plm --help
$ plm sow --help
harvest
Collect changed files from your home directory back into granaries. This is the opposite of sow.
Synopsis
plm harvest [OPTIONS] [-a GRANARY::PATH ...]
Description
The harvest command reads your configuration and estate files, detects which managed files have been modified in your home directory, and copies them back to their respective granaries. It:
- Compares files in HOME with versions in granaries using SHA256 hashing
- Copies only changed files back to granaries
- Supports adding new files to estate tracking via
-a/--add-to-estate - Handles template files (preserves
.j2suffix in granaries) - Updates estate files to reflect current state
- Shows colored diffs in verbose mode
Use cases:
- You manually edited a config file in HOME and want to sync it back to your dotfiles repo
- You want to backup changes made on one machine to your central dotfiles repository
- You're migrating configs and need to collect all changes
Options
-v, --verbose
Increase verbosity level. Can be stacked multiple times.
Level 0 (default): Minimal output, only errors shown
$ plm harvest
(no output if no changes)
Level 1 (-v): Show which files are being harvested
$ plm harvest -v
☑️ Harvesting /home/user/.bashrc to /home/user/dotfiles/bash/.bashrc
☑️ Harvesting /home/user/.gitconfig to /home/user/dotfiles/git/.gitconfig.j2
Level 2 (-vv): Show file diffs during harvest
$ plm harvest -vv
☑️ Harvesting /home/user/.bashrc to /home/user/dotfiles/bash/.bashrc
@@ -1,5 +1,5 @@
# My bash configuration
# Aliases
-alias ll='ls -l'
+alias ll='ls -la'
alias gs='git status'
Level 3+ (-vvv): Maximum verbosity with full tracebacks on errors
When verbosity is enabled, Python tracebacks will show full stack traces for debugging.
-n, --dry-run
Perform a trial run without making any changes to the filesystem.
$ plm harvest --dry-run
☑️ Would harvest /home/user/.bashrc to /home/user/dotfiles/bash/.bashrc
☑️ Would harvest /home/user/.gitconfig to /home/user/dotfiles/git/.gitconfig.j2
Useful for:
- Previewing what would be collected
- Testing before committing changes to your dotfiles repo
- Understanding which files have diverged
Can be combined with verbose flags:
$ plm harvest --dry-run -vv
☑️ Would harvest /home/user/.bashrc to /home/user/dotfiles/bash/.bashrc
@@ -1,5 +1,5 @@
# My bash configuration
-alias ll='ls -l'
+alias ll='ls -la'
-a, --add-to-estate
Copy new files into a granary. Format: granary_name::path
$ plm harvest -a mydots::/home/user/.newconfig
☑️ Harvesting /home/user/.newconfig to /home/user/dotfiles/mydots/.newconfig
This option:
- Immediately copies the file to the named granary
- Leaves estate tracking unchanged; the next
sowtracks the new granary file normally - Requires the granary to have a
namefield in its.plowman/plowman.ymlconfig - Can specify multiple paths:
-a name1::/path1 name2::/path2
Example with multiple paths:
$ plm harvest -a shell::/home/user/.zshrc shell::/home/user/.zprofile
☑️ Harvesting /home/user/.zshrc to /home/user/dotfiles/shell/.zshrc
☑️ Harvesting /home/user/.zprofile to /home/user/dotfiles/shell/.zprofile
Error handling:
If the granary name doesn't exist:
$ plm harvest -a nonexistent::/home/user/.file
Error: Granary name 'nonexistent' not found. Available names: shell, editor, git
If format is invalid:
$ plm harvest -a /home/user/.file
Error: Invalid format for --add-to-estate: '/home/user/.file'. Expected format: granary_name::path
-h, --help
Show help for the harvest command.
$ plm harvest --help
usage: plm harvest [-h] [-v] [-n] [-a [ADD_TO_ESTATE ...]]
options:
-h, --help show this help message and exit
-v, --verbose increase the level of verbosity
-n, --dry-run perform a trial run with no changes made
-a, --add-to-estate paths to add to estate and harvest (format: name::path)
Output Format
Success Messages
Files being harvested:
☑️ Harvesting /source/path to /destination/path
Files that would be harvested (dry-run):
☑️ Would harvest /source/path to /destination/path
Diff Output
Diffs use unified diff format with color coding:
- Cyan: Hunk headers (
@@ -1,5 +1,5 @@) - Yellow/Bold: File paths (
--- old,+++ new) - Green: Added lines in crop (
+new content) - Red: Removed lines from seed (
-old content) - Default: Context lines (unchanged)
Example:
@@ -1,5 +1,5 @@
# My bash configuration
# Aliases
-alias ll='ls -l'
+alias ll='ls -la'
alias gs='git status'
Note: For harvest, the "old" version is from the granary (seed) and the "new" version is from HOME (crop).
Error Messages
Errors are printed to stderr with red coloring when available.
Common errors:
- Invalid
--add-to-estateformat - Granary name not found
- Permission denied when writing to granary
- File doesn't exist in HOME
Exit Codes
- 0: Success - operation completed successfully
- 1: Error - operation failed (see error message for details)
Common error scenarios:
- Missing configuration file
- Invalid
--add-to-estateformat - Granary name not found
- Permission denied
- Template rendering errors (shouldn't occur in harvest, but possible)
Configuration Requirements for Harvest
Granary Naming
To use -a/--add-to-estate, granaries must have a name field in their per-path config:
# ~/dotfiles/.plowman/plowman.yml
shell:
name: myshell # This name is used with --add-to-estate
templates:
- .bashrc.j2
- .zshrc.j2
editor:
name: myeditor
templates:
- init.vim.j2
Then use the name with harvest:
$ plm harvest -a myshell::/home/user/.newconfig
Examples
Basic harvest
$ plm harvest
Preview changes
$ plm harvest --dry-run
Verbose harvest
$ plm harvest -v
Verbose with diffs
$ plm harvest -vv
Dry-run with verbose output
$ plm harvest --dry-run -vv
Add new file to estate and harvest
$ plm harvest -a myshell::/home/user/.tmux.conf
Add multiple files
$ plm harvest -a myshell::/home/user/.tmux.conf myshell::/home/user/.screenrc
Harvest with maximum verbosity for debugging
$ plm harvest -vvv
Tips
Workflow: Edit → Harvest → Commit
Typical workflow when you make manual changes:
# 1. Edit a config file directly in HOME
$ nvim ~/.bashrc
# 2. Preview what changed
$ plm harvest --dry-run -vv
# 3. Harvest the changes back to granary
$ plm harvest -v
# 4. Review and commit to your dotfiles repo
$ cd ~/dotfiles
$ git status
$ git add bash/.bashrc
$ git commit -m "Update bashrc with new aliases"
$ git push
Sync Across Machines
Harvest changes on one machine, then sow on another:
# On Machine A (where you made changes)
$ plm harvest -v
# Commit and push to Git
$ cd ~/dotfiles
$ git add .
$ git commit -m "Sync changes from Machine A"
$ git push
# On Machine B
$ cd ~/dotfiles
$ git pull
$ plm sow -v
Combining Flags
Flags can be combined in various ways:
# These are equivalent
$ plm harvest -vvv
$ plm harvest -v -v -v
$ plm harvest --verbose --verbose --verbose
# Dry-run with verbosity
$ plm harvest -n -vv
$ plm harvest --dry-run -vv
# Add to estate with verbosity
$ plm harvest -a myshell::/path -v
Quick Verification
After editing configs in HOME:
# Quick check of what changed
$ plm harvest --dry-run -v
# See detailed diffs
$ plm harvest --dry-run -vv
# Harvest if satisfied
$ plm harvest
Debugging Issues
If something goes wrong:
# Maximum verbosity shows full tracebacks
$ plm harvest -vvv
# Or combine with dry-run to see issues without making changes
$ plm harvest --dry-run -vvv
Silent Operation
For scripts or cron jobs:
# Only errors will be shown
$ plm harvest 2>/dev/null
# Or redirect all output
$ plm harvest >/dev/null 2>&1
Template Files
When harvesting template files:
- The file in HOME has no
.j2extension (e.g.,.bashrc) - The file in granary has
.j2extension (e.g.,.bashrc.j2) - Harvest automatically handles this mapping
- The harvested file preserves the
.j2extension in the granary
# HOME has: ~/.bashrc (rendered, no .j2)
# Granary has: ~/dotfiles/bash/.bashrc.j2 (template)
$ plm harvest -v
☑️ Harvesting /home/user/.bashrc to /home/user/dotfiles/bash/.bashrc.j2
Troubleshooting
"Granary name not found" Error
Make sure the granary has a name field in .plowman/plowman.yml:
# Check this file exists and has a name
cat ~/dotfiles/.plowman/plowman.yml
No Changes Detected
Harvest only collects files that differ between HOME and granary. If files are identical, nothing happens. Use --dry-run -vv to verify.
Permission Denied
Ensure you have write access to the granary directories:
$ ls -la ~/dotfiles/
Fix permissions if needed:
$ chmod -R u+w ~/dotfiles/
Tips
Combining Flags
Flags can be combined in various ways:
# These are equivalent
$ plm sow -vvv
$ plm sow -v -v -v
$ plm sow --verbose --verbose --verbose
# Dry-run with verbosity
$ plm sow -n -vv
$ plm sow --dry-run -vv
Quick Verification
After making changes to your granaries:
# Quick check of what changed
$ plm sow --dry-run -v
# See detailed diffs
$ plm sow --dry-run -vv
# Apply if satisfied
$ plm sow
Debugging Issues
If something goes wrong:
# Maximum verbosity shows full tracebacks
$ plm sow -vvv
# Or combine with dry-run to see issues without making changes
$ plm sow --dry-run -vvv
Silent Operation
For scripts or cron jobs where you don't want output:
# Only errors will be shown
$ plm sow 2>/dev/null
# Or redirect all output
$ plm sow >/dev/null 2>&1
Note: plowman doesn't have a quiet flag, so use shell redirection if needed.