task-while
v0.0.9
Published
Git-first task orchestrator for task-source workspaces
Maintainers
Readme
task-while
task-while is a git-first harness runtime built around a task source protocol. The published package name and CLI binary are both task-while.
It reads workflow settings from while.yaml, opens the configured task source, executes one task at a time, reviews the result, integrates approved work, and creates one git commit per completed task. The built-in task sources are spec-kit, which consumes spec.md, plan.md, and tasks.md under specs/<feature>/, and openspec, which consumes an OpenSpec change under openspec/changes/<change>/.
It also provides a standalone batch command for YAML-driven file processing that is independent from the feature/task harness runtime workflow.
Requirements
- Node.js 24 or newer
- For
run: a git repository with an initial commit - For
run: a workspace with the directory layout required by the selected task source - For
run: the files required by the selected task source - For
run: a clean worktree beforerun
Current built-in source requirements:
task.source: spec-kitspecs/<feature>/spec.mdspecs/<feature>/plan.mdspecs/<feature>/tasks.mdtask.source: openspecopenspec/changes/<change>/proposal.mdopenspec/changes/<change>/design.mdopenspec/changes/<change>/tasks.md- At least one file under
openspec/changes/<change>/specs/**/*.md
Install
pnpm add -D task-whileRun it with:
pnpm exec task-while runConfiguration
while.yaml configures the run workflow only. When it is absent, the CLI runs task.source: spec-kit, task.maxIterations: 5, and workflow.mode: direct with codex for both roles. task.source currently accepts only spec-kit or openspec. Each workflow role accepts provider-specific model, effort, and optional timeout in milliseconds.
task:
source: spec-kit
maxIterations: 5
workflow:
mode: direct
roles:
implementer:
model: gpt-5-codex
effort: high
timeout: 900000
reviewer:
model: gpt-5-codex
effort: high
timeout: 900000Current status:
workflow.roles.<role>.provideracceptscodexorclaude; when omitted it defaults tocodex, including roles that only setmodeland/oreffortworkflow.roles.<role>.timeoutis optional and sets a per-turn timeout in milliseconds for local agent runs; valid values are positive integers up to2147483647codexeffortacceptsminimal,low,medium,high, orxhighclaudeeffortacceptslow,medium,high, ormaxworkflow.mode: directrequiresimplementerandreviewerto use identicalmodel,effort, andtimeoutwhen they share the same providerworkflow.mode: directuses a local reviewerworkflow.mode: pull-requestpushes a task branch, polls GitHub PR review fromchatgpt-codex-connector[bot], then squash-merges on approval- in
workflow.mode: pull-request, reviewerproviderselects the remote reviewer; local reviewermodel,effort, andtimeoutvalues are ignored and no local reviewer agent is initialized workflow.mode: pull-requestcurrently supports onlycodexas the remote reviewer providertask.maxIterationsuses the same configured limit for every task in the selected source session; run workflow retries share a single per-task budget across phases
Example pull-request mode:
workflow:
mode: pull-request
roles:
implementer:
provider: claude
model: claude-sonnet-4-6
effort: max
reviewer:
provider: codexWorkspace Resolution
task-while run resolves the current working directory as the workspace root.
task.source: spec-kitrequirescwd/specstask.source: openspecrequirescwd/openspec/changes- if the required source root is missing, the CLI fails with a clear user-facing error
Feature resolution order:
--feature- current git branch prefix for
spec-kit - the only entry under the selected source root
For task.source: openspec, --feature identifies the OpenSpec change id.
Commands
task-while run
Runs the current feature workflow from the existing .while state or initializes a new one. Run it from the workspace root so the current directory contains the source-specific root, such as specs/ for spec-kit or openspec/changes/ for openspec.
cd /path/to/workspace
pnpm exec task-while run --feature 001-demoUseful flags:
--feature <featureId>: select the feature explicitly- For
task.source: openspec,--feature <featureId>selects the OpenSpec change id --until-task <taskSelector>: stop after the target task reachesdone--verbose: stream direct provider details tostderr, including Claude init/task/tool/result summaries and Codex thinking, commands, MCP tools, file updates, todo changes, messages, and final usage
task-while batch
Runs a standalone YAML-driven batch job. This command does not read while.yaml, does not require specs/, and does not use the task-source workflow.
cd /path/to/workspace
pnpm exec task-while batch --config ./batch.yamlBatch config example:
provider: claude
model: claude-sonnet-4-6
effort: max
timeout: 300000
glob:
- 'src/**/*.{ts,tsx}'
prompt: |
Read the target file and return structured output for it.
schema:
type: object
properties:
summary:
type: string
tags:
type: array
items:
type: string
required:
- summaryBatch behavior:
globis optional and defaults to**/*globis resolved relative to the directory that containsbatch.yamlprovider,prompt, andschemaare requiredmodel,effort, andtimeoutare optional and are forwarded to the selected provider client- batch
provideracceptscodexorclaude - batch
codexeffortacceptsminimal,low,medium,high, orxhigh - batch
claudeeffortacceptslow,medium,high, ormax - batch
timeoutis an optional per-file timeout in milliseconds; valid values are positive integers up to2147483647 - each run scans files under the
batch.yamldirectory and filters them byglob - structured results are written beside the YAML file in
results.json - internal harness state is written under
.while/beside the YAML file - result keys are relative to the directory that contains
batch.yaml --verbosestreams batch-level progress and direct provider details tostderrduring batch execution, including the current file, completion counts, Claude init/task/tool/result summaries, and Codex thinking, commands, MCP tools, file updates, todo changes, messages, and final usage- rerunning the command resumes unfinished work and skips files that already have accepted results
- failed files are suspended and retried after all pending files are processed
- file-level retries are limited by
maxRetries(default 3); exhausted files are marked blocked - when
globmatches no files, the command exits successfully without initializing a local agent
Task Lifecycle
Each task follows an explicit phase sequence:
workflow.mode: directrunsimplement -> verify -> review -> integrateworkflow.mode: pull-requestrunsimplement -> verify -> checkpoint -> review -> integrate
Implementation and review prompts are rebuilt on demand from the task source for the current task. Runtime-only context such as retry findings, changed files, and implement output is added in the workflow prompt layer rather than being cached as a separate contract artifact.
Completion requires all of the following:
- review verdict
pass - no findings
- every acceptance check passing
Review context uses actualChangedFiles derived from git diff against HEAD. In pull-request mode, changed-file context comes from the live PR snapshot instead of the local worktree diff.
Run scheduling is source-order only: task-while executes tasks in the order returned by the selected task source. The built-in task sources do not expose a dependency-graph executor.
In pull-request mode:
- review creates or reuses
task/<slug>and an open PR againstmain - if an open PR exists but the local task branch is missing, review restores the branch from
origin/task/<slug> - review creates a checkpoint commit with
checkpoint: Task <taskId>: <title> (attempt <n>) - review polls every minute with no default timeout
- review evaluates approval from a fully paginated live GraphQL PR snapshot
- approval is driven by the freshest
chatgpt-codex-connector[bot]signal after the checkpoint commit - active feedback includes unresolved, non-outdated review threads plus reviewer-authored review summaries and discussion comments after the current checkpoint
- process restart re-enters
revieworintegrateand continues the same PR flow - if the PR was already squash-merged before state was persisted, integrate treats it as already completed and finalizes local cleanup on resume
- integrate checks the task source completion marker, creates the final task commit when needed, squash-merges, returns to
main, and deletes the local task branch
Completion is git-first:
- one completed task = one git commit
.whileis runtime state and is not committed- completed task state stores
commitSha
Built-in spec-kit Expectations
The built-in spec-kit task source parses raw Spec Kit task lines in file order. It does not require enhanced per-task metadata blocks.
Example:
## Phase 1: Core
- [ ] T001 Implement greeting
- [ ] T002 [P] Implement farewell
- [ ] T010 [P] [US1] Add scenario coverageCurrent built-in spec-kit behavior:
- task ordering follows the order in
tasks.md - explicit task dependencies are not extracted or scheduled; execution follows
tasks.mdorder - implement/review prompts include the current task line, the current phase,
spec.md,plan.md, and the fulltasks.md - completion is still written back through
tasks.mdcheckboxes
Built-in openspec Expectations
The built-in openspec task source consumes an existing OpenSpec change directory and aligns implement/review prompts with openspec instructions apply --json.
Example configuration:
task:
source: openspec
maxIterations: 5Example run:
pnpm exec task-while run --feature example-changeCurrent built-in openspec behavior:
--featuremaps toopenspec/changes/<change>- stable task handles come from explicit numbering in
tasks.md, such as1.1and2.3 - execution follows the task order in
tasks.md; there is no dependency graph layer for built-in OpenSpec changes - implement/review prompts include the current task, task group,
proposal.md,design.md, expandedspecs/**/*.md, fulltasks.md, and the OpenSpec apply instruction/state/progress - completion is still written by
task-whileafter review/integrate success; it does not adopt/opsx:apply's immediate checkbox update behavior task-whileconsumes OpenSpec artifacts and CLI JSON, but it does not run/opsx:propose
Task retry budget is configured globally in while.yaml:
task:
maxIterations: 2What task-while Does Not Do
task-while does not replace Spec Kit's project-level workflow. It does not run Spec Kit commands, checklists, or hooks.
Its contract with the selected task source is simple:
- the task source parses source artifacts and provides prompts plus completion operations
- the harness runtime drives implement, review, integrate, and persistence around that protocol
The standalone batch command is separate from this contract. It does not use task sources, run-task queue scheduling, review/integrate stages, or git-first completion.
Architecture
task-while uses a state-machine control plane:
- TaskState per subject is the single source of truth, written atomically as JSON
- Transition log (append-only JSONL) records phase transitions for debugging
- Artifacts store large structured outputs (implementations, reviews, checkpoints, integrate results) separately
- A pure kernel interpreter executes action-only workflow programs driven by declarative transition tables
- A session layer drives multi-subject scheduling via pluggable schedulers
- All external effects flow through explicit ports (AgentPort, GitHubPort, GitPort)
runandbatchboth create the same local structuredAgentPortat the command boundary; programs only consume that port and keep prompt construction in the workflow/program layer
Runtime Layout
run keeps runtime state under:
<source-entry>/<id>/.while/
state/<protocol>/<subject-id>.json — TaskState per subject (truth)
transitions/<protocol>/<subject-id>.jsonl — TransitionRecord log (debug)
artifacts/<protocol>/<subject-id>/*.json — Artifact per kind/iteration.while is runtime state, not the long-term source of truth. Resume reads the state file directly — no event replay needed.
batch keeps runtime files beside the YAML config:
<config-dir>/
├── batch.yaml
├── results.json
└── .while/
├── state/batch/*.json
├── transitions/batch/*.jsonl
└── artifacts/batch/...results.json maps accepted structured output by file path relative to the batch.yaml directory. If the config lives under a subdirectory and uses patterns such as ../input/*.txt, the keys keep that relative form.
Publishing
Before publishing:
pnpm lint
pnpm typecheck
pnpm test
npm pack --dry-run