Calq Dev
Calq Dev is a durable workflow automation tool. Designed for failure-proof local development automation without manual tool orchestration.
Comparison
Project Scaffolding & Automation
| Feature | Calq Dev | Project Scaffolders | Task Runners | Monorepo Orchestrators | Shell Scripts |
|---|---|---|---|---|---|
| Crash recovery (resume after failure) | ✅ durable per step | ❌ | ❌ | ⚠️ input-hash cache hits only | ❌ |
| End-to-end project setup (scaffold + CI + repo) | ✅ single command | ⚠️ scaffold only | ❌ user-composed tasks | ⚠️ workspace init only | ⚠️ manual scripting |
| Organization-wide consistency | ✅ clones shared repos (.github, .license) | ⚠️ template repos | ❌ | ⚠️ generators | ⚠️ manual setup |
| Multi-language format pipeline | ✅ guard-based step skipping | ❌ not a formatter | ⚠️ user-defined tasks | ⚠️ per-project config | ⚠️ manual conditionals |
| Configuration portability (presets, Codespaces) | ✅ named presets + auto dotfiles | ❌ | ❌ | ❌ | ⚠️ manual dotfiles |
| Configurable without code changes | ✅ JSON config | ⚠️ template editing | ⚠️ Makefile/Justfile editing | ⚠️ config files | ❌ script editing |
| Custom project types | ✅ JSON-defined command lists | ✅ custom generators | ✅ user-defined tasks | ✅ workspace generators | ✅ any script |
| Ecosystem / language reach | ⚠️ .NET-centric defaults | ✅ language-agnostic | ✅ language-agnostic | ✅ language-agnostic | ✅ any tool |
Git Workflow
| Feature | Calq Dev | Git Flow Tools | GitHub CLI + Scripts | Git Hooks | IDE Git Integrations |
|---|---|---|---|---|---|
| Crash recovery (resume after failure) | ✅ durable per step | ❌ | ❌ | ❌ | ❌ |
| Issue-to-branch-to-PR in single commands | ✅ built-in (switch, push, merge) |
⚠️ branch only | ⚠️ multi-command | ❌ | ⚠️ varies by IDE |
| Compound operations (merge + close + cleanup) | ✅ single command | ⚠️ manual steps | ⚠️ multi-command | ❌ | ⚠️ varies by IDE |
| Stash-safe branch switching | ✅ automatic stash/restore | ❌ | ❌ | ❌ | ✅ some IDEs |
| Configurable workflow (strategy, PR format) | ✅ JSON presets + dotfiles sync | ⚠️ opinionated | ⚠️ manual flags | ❌ | ✅ settings-based |
| Shell completion (issue numbers) | ✅ built-in | ❌ | ✅ gh completions |
❌ | ✅ built-in |
| No dedicated infrastructure | ✅ git + gh CLI only | ✅ git only | ✅ gh + git | ✅ git hooks | ✅ IDE-native |
Table of Contents
- Comparison
- Usage - Calq Dev
- Quick Start
- License
Usage - Calq Dev
1. Foundations
1.1 Installation
Calq Dev is distributed as a .NET global tool.
dotnet tool install -g CalqFramework.Dev.Cli
Verify installation:
dev --help
Key points:
- Requires
dotnet,git, andghCLI on the systemPATH - All subcommands are available immediately after installation
1.2 Configuration directory
Configuration files are stored in a single directory and created automatically on first use with sensible defaults.
- Standard:
{AppData}/dev(e.g.,~/.config/devon Linux,%APPDATA%/devon Windows) - Codespaces:
~/dotfiles/.config/dev(see 1.3 Codespaces support)
Key points:
- No manual setup required — all configuration files are generated with defaults on first access
- Files follow the naming convention
{FullTypeName}.{preset}.json
1.3 Codespaces support
When the CODESPACES environment variable is detected, the configuration directory resolves to ~/dotfiles/.config/dev/ instead of the standard platform path.
Key points:
- Detection is automatic — no user intervention required
- Enables persistent configuration across ephemeral Codespaces instances via the dotfiles repository
1.4 Preflight checks
Before executing a multi-step pipeline, Calq Dev verifies that all required external tools are available on PATH.
Key points:
- Applies to
dev new(checksdotnet,gh,git) anddev format(checks tools referenced in pipeline steps) - Failures are reported before any work begins — no partial execution from missing dependencies
See also: 1.1 Installation
1.5 Crash recovery
Calq Dev is built on Calq CMD, a durable execution framework. All multi-step operations persist progress after each completed step. If a command is interrupted or fails mid-execution, re-running the same command resumes from the last completed step.
Key points:
- Applies to all pipelines: scaffolding, formatting, and git workflow commands
- No manual cleanup required after interruption — re-run the command to continue
- Completed steps are not re-executed on resume
2. Configuration & Customization
2.1 Preset switching
All configuration POCOs are grouped under a workflow preset. Switching the preset reloads all subcommand configurations from the new preset's JSON files.
# Print current preset
dev config preset
# Switch to a different preset
dev config preset my-workflow
Key points:
- All config POCOs use
[PresetGroup("Workflow")]— switching the master preset'sWorkflowvalue cascades to all of them - Config files follow the naming convention
{FullTypeName}.{preset}.json - Enables maintaining separate configurations for different workflows (e.g., personal projects vs team projects)
See also: 1.2 Configuration directory
2.2 Setting individual values
dev config set modifies a single configuration value by class name and dot-separated property path.
dev config set NewConfig Organization my-org
dev config set PushConfig MainBranch develop
dev config set MergeConfig MergeStrategy rebase
dev config set FormatConfig Steps.0.Command "dotnet build {dir}"
Print config directory path:
dev config path
Key points:
- The first argument is the config class name, the second is the property path, and the third is the value
- Changes are persisted to the JSON file immediately
- Edit JSON files directly as an alternative to
dev config set
See also: 1.2 Configuration directory, 2.1 Preset switching
2.3 Dotfiles sync
Sync configuration with a dotfiles repository for portability across machines and Codespaces instances.
# Push local config to dotfiles repo
dev config push
# Pull config from dotfiles repo
dev config pull
Key points:
pushcopies config files to~/dotfiles/.config/dev/, commits, and pushespullcopies from~/dotfiles/.config/dev/to the local config directory- Enables consistent configuration across ephemeral environments
See also: 1.3 Codespaces support, 1.2 Configuration directory
2.4 PipelineStep model
All configurable pipelines (format, pull, relock, issues) share the same step model.
| Property | Type | Description |
|---|---|---|
Command |
string | Shell command. Supports {dir} and {target} placeholders. |
FilePattern |
string? | Glob pattern — step is skipped if no matching files exist. |
TargetPatterns |
list of list of string? | Ordered glob-pattern groups for target discovery. First group yielding exactly one file wins; otherwise all results are combined. When null, command runs once with {dir} only. |
Key points:
FilePatternacts as a guard: if no files match the pattern in the target directory, the step is skipped entirelyTargetPatternsenables per-file execution: the step runs once for each discovered target, substituting{target}in the command- When
TargetPatternsis null, the command executes once with only{dir}available as a placeholder
2.5 Naming conventions
The project name follows the Organization.Project convention.
dev new classlib CalqFramework.Something
Key points:
- The part after the first dot is kebab-cased into the project subdirectory name (e.g.,
CalqFramework.Somethingcreates asomething/directory) - Projects and solutions use the full name (e.g.,
CalqFramework.Something.csproj,CalqFramework.Something.sln)
2.6 Custom project types
Edit NewConfig to define custom project types, modify the scaffolding steps, or customize .csproj injection rules.
Add a custom project type:
dev config set NewConfig ProjectTypes.webapp "[\"dotnet new webapp -n {projectFullName} -o {projectFullName}\", \"dotnet new sln -n {projectFullName}\", \"dotnet sln add {projectFullName}\"]"
Or edit the JSON file directly at {configDir}/CalqFramework.Dev.Config.NewConfig.{preset}.json:
{
"ProjectTypes": {
"classlib": ["dotnet new classlib -n {projectFullName} -o {projectFullName} {langFlag}", "..."],
"webapp": ["dotnet new webapp -n {projectFullName} -o {projectFullName}", "dotnet new sln -n {projectFullName}", "dotnet sln add {projectFullName}"]
}
}
Available template placeholders:
| Placeholder | Value |
|---|---|
{organization} |
GitHub organization |
{projectFullName} |
Full project name (e.g., CalqFramework.Dev) |
{kebabName} |
Kebab-case name (e.g., dev) |
{name} |
Name suffix after first dot (e.g., Dev) |
{langFlag} |
-lang "F#" or empty |
{initialVersion} |
Initial version string |
{visibility} |
--public, --private, or --internal |
{ghRepoFlags} |
Additional gh repo create flags |
{dir} |
Current directory (.) |
{tempDir} |
Temporary directory for optional clone steps |
Customize .csproj injection:
{
"ProjXml": {
"classlib": {
"PackageId": "{projectFullName}",
"Version": "{initialVersion}",
"Authors": "My Team"
},
"webapp": {
"Version": "{initialVersion}"
}
}
}
See also: 2.2 Setting individual values, 2.5 Naming conventions
2.7 Custom format pipeline
Edit FormatConfig to replace or extend the formatting steps.
Example: minimal pipeline (dotnet format only):
{
"Steps": [
{ "Command": "dotnet build --no-restore {target}", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]] },
{ "Command": "dotnet format {target} --severity info", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]] },
{ "Command": "dotnet build --no-restore {target}", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]] }
]
}
Example: add a custom linter step:
{
"Steps": [
{ "Command": "dotnet build --no-restore {target}", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]] },
{ "Command": "my-custom-linter {dir}", "FilePattern": "*.cs" },
{ "Command": "dotnet format {target} --severity info", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]] },
{ "Command": "dotnet build --no-restore {target}", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]] }
]
}
Example: multi-language pipeline (Rust + .NET):
{
"Steps": [
{ "Command": "dotnet build --no-restore {target}", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]], "FilePattern": "*.csproj" },
{ "Command": "dotnet format {target} --severity info", "TargetPatterns": [["*.sln", "*.slnx"], ["*.*proj"]], "FilePattern": "*.csproj" },
{ "Command": "cargo fmt --manifest-path {target}", "TargetPatterns": [["Cargo.toml"]], "FilePattern": "Cargo.toml" }
]
}
See also: 2.4 PipelineStep model, 1.4 Preflight checks
2.8 Custom git workflow
Each git workflow subcommand is driven by its own configuration POCO.
SwitchConfig:
{
"BranchPrefix": "issues/",
"AutoCreateIssue": true
}
PushConfig:
{
"Remote": "origin",
"MainBranch": "main",
"ForceWithLeaseOnFeature": true,
"CreatePr": true,
"PrTitleFormat": "(#{IssueID}) {IssueTitle}"
}
MergeConfig:
{
"MergeStrategy": "squash",
"DeleteBranch": true,
"CloseIssue": true,
"PullAfterMerge": true
}
UtilityConfig (pull, relock, issues):
{
"Pull": [{ "Command": "git pull --rebase --autostash origin main" }],
"Relock": [{ "Command": "dotnet restore --no-cache --force-evaluate --use-lock-file" }],
"Issues": [{ "Command": "gh issue list --limit 20 --search \"is:open no:assignee sort:created-desc\"" }],
"IssueCompletionCommand": "gh issue list --limit 20 --json number --jq \".[].number\""
}
Key points:
- All utility commands use the same
PipelineStepmodel asFormatConfig - Edit via
dev config setor directly in the JSON files
See also: 2.4 PipelineStep model
3. Project Scaffolding
3.1 Scaffolding pipeline
dev new executes a full scaffolding pipeline from a single command: creates projects, solutions, references, injects .csproj metadata, seeds GitHub workflow templates, and optionally creates a GitHub repository.
# Scaffold a classlib with test project
dev new classlib CalqFramework.Foo
# Scaffold a console app
dev new console CalqFramework.Bar
# Scaffold a tool (library + CLI + tests)
dev new tool CalqFramework.Baz
# Create a public GitHub repo during scaffolding
dev new classlib CalqFramework.Foo --public
# Override language and organization
dev new classlib CalqFramework.Foo --lang "F#" --organization my-org
What new does automatically:
- Clones
.githuband.licenserepos from the organization (optional — warns on failure) - Runs
dotnet newfor each project in the template - Creates the solution and adds project references
- Injects
.csprojXML properties (PackageId,Version,RootNamespace, etc.) - Seeds
.github/workflows/fromworkflow-templates/if present - Optionally runs
git init+gh repo create+ initial push
Key points:
- Project types are fully configurable — add your own via
NewConfig.ProjectTypes .csprojinjection is template-aware: different XML properties forclasslibvsconsolevsxunit
See also: 2.6 Custom project types, 1.5 Crash recovery, 2.5 Naming conventions
3.2 Built-in project types
| Type | Projects Created |
|---|---|
classlib |
Library + xUnit test project + solution |
console |
Console app + solution |
tool |
Library + CLI console + xUnit test project + solution |
Key points:
- Each type defines an ordered list of shell commands executed during scaffolding
- All types support the
--langflag for language override
See also: 2.6 Custom project types, 3.1 Scaffolding pipeline
3.3 Organization repo cloning
The first step of the scaffolding pipeline clones .github and .license repositories from the configured organization into the new project directory.
Key points:
- Provides shared editor configuration, workflow templates, and license files
- Cloning is optional — the pipeline continues with a warning if the repositories do not exist
- The organization is configurable via
NewConfig.Organization
See also: 2.6 Custom project types
3.4 Workflow template seeding
If the cloned .github repository contains a workflow-templates/ directory, those templates are copied into the new project's .github/workflows/ directory.
Key points:
- Enables consistent CI/CD configuration across all projects in an organization
- Templates are copied once during scaffolding — subsequent changes to the templates do not propagate automatically
See also: 3.3 Organization repo cloning
3.5 GitHub repository creation
When the --public, --private, or --internal flag is passed, dev new creates a GitHub repository after scaffolding completes.
dev new classlib CalqFramework.Foo --public
Key points:
- Runs
git init,gh repo create, and pushes the initial commit - Visibility defaults to private when no flag is specified and repository creation is triggered
- Repository creation is skipped entirely when no visibility flag is provided
See also: 2.6 Custom project types
4. Code Formatting
4.1 Format pipeline
dev format executes a multi-step formatting pipeline. Each step is a shell command with optional file-pattern guards and per-target execution.
# Format current directory
dev format
# Format a specific directory
dev format --dir /path/to/project
Default pipeline:
| Step | Command | Condition |
|---|---|---|
| 1 | dotnet build --no-restore {target} |
Targets: *.sln, *.slnx → *.*proj |
| 2 | jb cleanupcode {dir} --profile="Built-in: Full Cleanup" |
Only if *.csproj files exist |
| 3 | fantomas {dir} |
Only if *.fsproj files exist |
| 4 | dotnet format {target} --verbosity diag --severity info |
Targets: *.sln, *.slnx → *.*proj |
| 5 | dotnet build --no-restore {target} |
Targets: *.sln, *.slnx → *.*proj |
Key points:
- Steps with
FilePatternare skipped when no matching files exist in the target directory - Steps with
TargetPatternsrun once per discovered target file, substituting{target}. Patterns are grouped by priority: the first group that yields exactly one file wins; otherwise all results are combined. - Placeholders:
{dir}= target directory,{target}= individual discovered target file - The entire pipeline is configurable via
FormatConfig
See also: 2.7 Custom format pipeline, 2.4 PipelineStep model, 1.4 Preflight checks
4.2 Multi-language support
The format pipeline supports multiple languages in a single repository by combining FilePattern guards with language-specific commands.
# A repository with both .NET and Rust code uses separate steps for each
dev format
Key points:
- Each step can target a different language via its
FilePattern(e.g.,*.csprojfor .NET,Cargo.tomlfor Rust) - Steps for languages not present in the target directory are automatically skipped
See also: 2.7 Custom format pipeline, 2.4 PipelineStep model
5. Git Workflow
5.1 Issue listing
dev issues lists open issues from GitHub.
dev issues
Default behavior: gh issue list --limit 20 --search "is:open no:assignee sort:created-desc"
Key points:
- The command is configurable via
UtilityConfig.Issues IssueCompletionCommandprovides issue number completion for shell auto-complete
See also: 2.8 Custom git workflow, 2.4 PipelineStep model
5.2 Issue-driven branching
dev switch creates or switches to an issue branch. Pass an issue number to branch from an existing issue, or a title to create a new issue automatically.
# Switch to branch issues/42
dev switch 42
# Create a new issue titled "Add logging" and switch to its branch
dev switch "Add logging"
Key points:
- Branch naming:
{BranchPrefix}{issueId}(default prefix:issues/) - When
AutoCreateIssueis enabled (default), passing a string creates a GitHub issue viaghand branches from its ID - Uses stash-apply safety: dirty working tree is stashed before switching and restored after
See also: 2.8 Custom git workflow, 5.1 Issue listing
5.3 Push
dev push pushes to remote with branch-aware behavior.
dev push
On main branch:
- Pulls with rebase first, then pushes to origin
On feature branch:
- Pulls with rebase first
- Pushes with
--force-with-lease(configurable) - Auto-creates a PR linking the issue from the branch name (configurable)
- PR title format:
(#42) Issue Title(configurable viaPrTitleFormat)
Key points:
- Force-with-lease prevents overwriting remote commits not present locally
- PR creation and title format are individually configurable
See also: 2.8 Custom git workflow, 5.2 Issue-driven branching
5.4 Merge
dev merge squash-merges the current feature branch PR and performs full cleanup.
dev merge
What merge does automatically:
- Pushes the current branch (calls
pushinternally) - Squash-merges the PR via
gh pr merge --squash --delete-branch - Closes the linked issue (if branch name contains an issue ID)
- Switches to main and deletes the local feature branch
- Pulls latest main
Key points:
- Cannot be run from main branch
- Merge strategy is configurable (
squash,merge,rebase) - Each step (delete branch, close issue, pull after merge) is individually toggleable
See also: 2.8 Custom git workflow, 5.3 Push, 5.2 Issue-driven branching
5.5 Pull
dev pull pulls from remote with rebase, regardless of current branch.
dev pull
Default behavior: git pull --rebase --autostash origin main
Key points:
- The pull command is configurable via
UtilityConfig.Pullusing the samePipelineStepmodel as the format pipeline
See also: 2.4 PipelineStep model
5.6 Dependency relocking
dev relock forces re-evaluation of the dependency graph and updates lock files.
dev relock
Default behavior: dotnet restore --no-cache --force-evaluate --use-lock-file
Key points:
- The command is configurable via
UtilityConfig.Relock
See also: 2.8 Custom git workflow, 2.4 PipelineStep model
Quick Start
dotnet tool install -g CalqFramework.Dev.Cli
dev --help
Scaffold a project:
dev new classlib MyOrg.MyLib
Format code:
dev format
Issue-driven workflow:
dev issues # list open issues
dev switch 42 # create branch issues/42
# ... make changes ...
dev push # push + auto-create PR
dev merge # squash-merge + cleanup
License
Calq Dev is licensed under the PolyForm Strict License with a Commercial Use Grant.