@dpeek/codeless
v0.1.5
Published
An attended planner and implementer workflow for parallel capability development
Readme
Codeless
Codeless is an attended workflow for parallel capability development. Each stream has one branch/worktree, one planner, an implementer shell, and at most one approved change. Work within a stream is sequential: propose, approve, implement, review, commit, land.
This project owns the executable, Pi extension, Git/Herdr mechanics, and tests. Project instructions and prompts belong to the consuming project. The package has its own dependencies, TypeScript configuration, and checks; it imports no consumer application code. Its tests use independent temporary repositories.
Installation
Codeless requires Bun, Git, Herdr, and Pi. Planner activation requires Herdr's
official Pi lifecycle integration; install it with herdr integration install pi
and restart existing Pi processes after updating it. The managed launch and
session-replacement contract is verified against Herdr 0.8.2 and Pi 0.85.1.
The scoped package is configured for public npm access. Once published, install it with either package manager:
bun add --global @dpeek/codeless
# or
npm install --global @dpeek/codelessThe package installs the codeless executable:
codeless --helpThe implemented workflow contract is in spec/workflow.md. Proposed and missing behavior is kept in todo/workflow.md.
Project configuration
Run codeless inside the intended Git checkout. The runner discovers the project
from the current working directory, including when invoked from a subdirectory
or through a linked executable. Its installation location does not select the
project. Help also works outside a repository.
Each project commits .codeless/config.json:
{
"integrationBranch": "main",
"directions": "todo",
"prompts": ".codeless/prompts",
"install": ["bun", "install", "--frozen-lockfile"],
"check": ["bun", "run", "check"],
"planner": {
"provider": "openai-codex",
"model": "gpt-5.6-sol",
"thinking": "high"
},
"implementer": {
"provider": "openai-codex",
"model": "gpt-5.6-terra",
"thinking": "medium"
}
}All fields are required. Directory paths are relative to the checkout and must
stay within it. Commands are nonempty argument arrays, executed in the target
worktree without shell interpolation. Each role requires an exact Pi provider
and model ID plus one of off, minimal, low, medium, high, xhigh, or
max. Configuration is trusted project code.
Before a role session starts, Codeless launches a short-lived, promptless Pi RPC process in the target worktree. It requires the exact provider/model in Pi's available-model response, selects it, requires the configured level in that model's available-thinking response, and verifies the resulting state. Failure identifies the role and requested selection; Codeless does not start agent work with Pi's fallback model or a clamped thinking level. Successful launch output shows the effective role selection, and the Pi process receives the same exact model and level.
The invoking checkout selects the integration branch. Keep that setting aligned across participating worktrees. The runner discovers its checkout from Git's worktree list. Directions, prompts, and install commands come from the target worktree; landing reads the check command after rebasing. Creating a stream first verifies its direction and prompts in the integration checkout.
Project prompt contract
The configured prompt directory provides change.md, implement.md,
review.md, and commit.md, using Pi prompt-template syntax. The runner supplies:
/change <stream-directory> <direction-file>to the planner;/implement <numbered-change-file>to the implementer;/review <numbered-change-file>to the planner after successful dispatch.
Path arguments are JSON-quoted. Each direction is <directions>/<slug>.md.
The project owns prompt contents, approval rules, review criteria, and the
transition from review to commit. codeless init creates missing copies of the
package's four generic starters, but never replaces existing prompt bytes.
Review and commit those local prompt edits in the invoking checkout, then bring
that commit onto the configured integration branch before creating streams.
Required prompts and directions must exist for stream creation and opening.
The package-owned planner extension admits each newly launched planner using
its exact <slug>-planner Pi name, <slug>_planner Herdr identity, managed
readiness, canonical worktree, and official Pi lifecycle integration. It checks
that all five planner tools are active before sending /change and binds the
admitted process, pane, worktree, name, and live session ID.
After landing, replacement activation uses a one-use ticket held in that Pi
process, bound to the new conversation's session ID. It verifies the local
identity, effective model/thinking selection, and tools without querying Herdr's
asynchronous status. Saved session entries cannot replay a handoff. Codeless
requires activation acknowledgement before submitting /change exactly once;
failed or cancelled handoffs never retry automatically. After a failed
replacement, exit Pi and reopen the stream from another Herdr shell. Herdr's
integration still supplies monitoring and external agent control. Global
installation of Codeless's extension is unnecessary.
The approval tool has no arguments. Its extension derives the active
<slug>-planner Pi session and passes it to the backing CLI, which requires it
to match the clean stream worktree and branch. That stream commit is the
proposal's base; approval does not compare it with a concurrently advancing
integration branch. The CLI validates the proposal, exclusively creates the next
monotonic changes/NNN.md, and records one hash-backed journal approval. Landing
later owns locked synchronization and any required rebase onto integration. Exact retries reconcile a missing
file or journal step; conflicting state stops. Approval returns the numbered path
but does not dispatch it. Dispatch uses the package executable, inherits the
planner's worktree, and queues review only on success. Pi loads the extension
explicitly at planner launch.
After landing and recording the full landed commit hash in planner.md, the
project's commit prompt calls next_stream_change with the completed
changePath and landedCommit. The tool requests /streams-next, an extension
command that waits for the current turn to settle, prepares the next loop, and
replaces the Pi session in the same pane. It preserves the planner name, applies
the planner selection read and validated after the stream fast-forwards to the
captured integration commit, then activates and verifies the replacement before
sending /change after resources reload. The previous conversation is not copied; the
journal and project files carry context. The fresh planner reads repository guidance,
its journal, and current direction first. It stops on wholly gated work, uses the
latest numbered change only for active or ambiguous recovery, and reads older changes
only for journal-linked unresolved decisions. After selecting an ungated candidate it
reads relevant contracts and implementation; after a fast-forward it also rereads
current direction and files affected by incoming commits, without mining deleted or
historical documents for work.
This uses Pi's newSession({ setup, withSession }) command API, verified with
Pi 0.85.1. Only the replacement context activates the selection and sends the
new prompt. Configuration changes take effect at the next role-session boundary,
not during an active planner or implementer. Review and remediation therefore
continue with their existing session's selection. Duplicate requests
while a handoff is pending are rejected. Ordinary session startup, waiting for
approval, failed validation, and cancelled replacement do not schedule another
loop. The project prompt still owns approval and stopping when no work remains.
Shared local state
Worktrees, proposals, numbered changes, and journals live in one shared local
workspace. By default it is .codeless/state/ in the primary checkout. That
directory is Git-ignored while .codeless/config.json, prompts, and guidance
remain tracked. Every linked worktree resolves the same primary-checkout state.
To put the state elsewhere, configure an absolute path once from any checkout:
git config --local codeless.workspaceRoot /absolute/path/to/workspaceThis local Git setting is shared by all worktrees. Keep the path stable while planners or worktree shells are running.
<primary-checkout>/.codeless/state/
stream/<slug>/
planner.md # decisions and outcomes
change.md # editable current proposal
changes/NNN.md # approved proposals
worktree/<slug>/ # stream/<slug> branch
worktree/main/ # example integration checkout location
.land-lock/ # shared landing owner and recorded integration commit
metrics/<slug>/NNN.json # dispatch/landing times and deduplicated implementer attemptsRun codeless init once after configuring a project. It creates missing generic
change.md, implement.md, review.md, and commit.md starters in the
configured in-project prompt directory, reporting each as created or preserved.
Existing prompt files are never replaced; review and commit generated files from
the editable invoking checkout, then bring that commit onto the configured
integration branch before creating streams. Init refuses to generate missing
prompts when invoked from the dedicated integration checkout.
It also creates the shared state layout and dedicated integration worktree at
<workspace>/worktree/<integration-branch> without requiring Herdr. For the
default workspace it adds only /.codeless/state/ to the primary checkout's
.gitignore; an absolute workspace override does not modify repository ignores.
It is safe to repeat when that exact worktree is registered. It stops rather
than moving a branch checkout, replacing an occupied target, or broadening a
repository ignore rule that covers configuration or prompts.
Normal git clean -fd preserves ignored state. git clean -fdx removes ignored
files and can therefore destroy local Codeless journals, metrics, and worktrees;
inspect its targets before using it.
Commands
Run creation and opening from a Herdr-managed operator shell outside the target planner/implementer panes. Herdr requires an available interactive shell in the target pane before it can start Pi. Landing needs no Herdr session.
codeless init
codeless create <slug>
codeless open <slug>
codeless approve <planner-session>
codeless dispatch <numbered-change-file>
codeless rework <numbered-change-file> <feedback>
codeless finish <numbered-change-file>
codeless land <slug>
codeless next <numbered-change-file> <landed-commit>
codeless metricsSlugs are lowercase kebab-case, at most 24 characters. init validates the
existing configuration and integration branch, validates all configured prompt
destinations before mutation, reports created or preserved starters plus the
branch, primary checkout, workspace, and integration worktree, then creates the
shared state directories and canonical integration worktree when absent. All other
commands validate their prerequisites and never bootstrap this setup. create starts
stream/<slug> from the integration branch and creates its local documents;
it refuses existing streams. open reuses the existing stream workspace and
one- or two-pane layout. It focuses an existing managed planner without installing
dependencies, sending another prompt, or replacing its conversation. To restart,
exit Pi deliberately, leave both stream panes at their shell prompts in the
stream worktree, then run codeless open <slug> from another Herdr shell.
When a planner must be started, creation/opening validates the available shells,
runs the configured install command and role preflight, adds a right-hand shell
only when absent, and uses herdr agent start for named, readiness-checked Pi
startup. It verifies the result before sending activation. An occupied or
mismatched pane, unmanaged agent, ambiguous layout, or failed startup stops;
Codeless never takes over an existing agent. Pi's display name is separate from
Herdr's managed agent name. Launch admission verifies both names, lifecycle
authority, and worktree; subsequent conversation replacements use the local
handoff described above. Codeless never renames an unmanaged process. There is
no direct planner command.
Dispatch validates the implementer selection before touching the planner's
right-hand pane, starts a fresh ephemeral implementer with Codeless's reporting
extension and its explicit Pi extension flag, and waits for completion. Rework verifies
that same change's idle implementer and worktree, invokes one package-owned Pi command
that verifies its immutable stream/change scope, arms reporting, and submits one feedback
turn with the same one-hour limit, records a rework
attempt, and returns it before review is queued again. Finish verifies that identity,
gracefully exits it, and waits for the right pane's stream-worktree shell. Neither operation
replaces the agent, changes its selection, retries, or continues after a mismatch, timeout,
blocked agent, or ambiguous pane. Its JSON result is a normalized attempt report, which the
planner tool exposes before queueing review. It includes the actual settled model/thinking selection,
terminal text and outcome, full-session Pi usage and available Pi cost estimate,
timestamps, and tool/error counts; prompts, source, thinking, credentials, and
transcripts are not retained.
The first valid dispatch creates one atomic local JSON metric record for its
stream and numbered change. Each accepted run receives a new attempt ID and is
added idempotently under that record; re-ingesting an ID preserves the original
attempt and retries preserve the original dispatch time. Missing, malformed, or
unwritable collection data warns and stores an incomplete attempt when possible
without retrying or failing a settled implementation. After a successful
integration fast-forward, Codeless records the landed time and commit on that
change's canonical record, creating a landed record without elapsed time when
dispatch collection was unavailable; collection warnings never alter dispatch or
landing.
codeless metrics prints every recorded stream and a project total. Its first
table reports dispatch-to-land wall-clock time; among landed changes, records
without a measured duration are explicitly unavailable. Dispatched-but-unlanded
changes remain a separate count. Its second table reports implementer attempts:
distinct changes with rework, initial and rework turns, incomplete collection,
exact stored terminal outcomes, and tool errors. Usage and cost coverage count
measured attempts separately from unavailable collection; token totals include
only measured usage, and cost totals remain grouped by recorded currency without
conversion. These counts do not establish implementation quality or review
success. Metrics are prospective local observations, not journal state or a
recovery mechanism.
Landing requires clean stream and integration worktrees and exactly one stream
commit outside their merge base. It acquires .land-lock atomically, recording
the owner and integration commit. It rebases if necessary, runs the configured
check command, requires the checked worktree to remain clean, and fast-forwards
the integration checkout. Success releases the lock. Other branches and
checkouts are untouched; no push is performed.
Another lock owner causes a stop, without queuing or polling. Rebase conflicts
or failed checks retain ownership. During conflict resolution, run focused checks
when useful; rerun land for the configured full check, which it alone owns.
It verifies the recorded integration commit has not changed. To abandon a landing,
inspect the owner/base and Git state before manually removing the lock. There is
no automatic stale-lock removal or retry.
next is the session handoff's preparation command. It requires the stream's
own clean worktree and latest numbered change, a full commit hash present in its
journal, that commit in the stream's history, and all stream commits included
in the configured integration branch. A landing lock owned by this stream or
with an unknown owner stops preparation; another stream's lock does not block
planning. It fast-forwards to a captured integration commit, verifies project
prompts, direction, and planner selection, and returns JSON containing
sessionName, prompt, and the validated selection. It does not modify
journals, allocate a change, approve implementation, or
control Pi itself. Preparation can be repeated safely after inspecting a failure.
If validation or session replacement fails, the planner stops for operator attention. Landing is already complete, and any preparation fast-forward remains applied. There is no background retry; exit Pi and reopen the stream from another Herdr shell to recover from the journal and Git state.
Package development
From this package directory, run bun run check for formatting, lint, types,
and tests, or bun run test for tests alone. The integration tests use real Git
worktrees and mock Herdr/Pi commands; they never launch actual agents.
From a clean main checkout, publish the next patch release with:
bun run releaseThe script verifies npm authentication, runs the full check and an npm package
dry run, increments the patch version, commits package.json with the version as
the complete commit message, creates the matching version tag, and publishes
@dpeek/codeless. It intentionally does not push the commit or tag.
For non-interactive local publishing, create an npm granular access token with
read/write access to @dpeek/codeless (or the @dpeek scope) and Bypass 2FA
enabled. Put the token in the repository's ignored .env file:
NPM_TOKEN=npm_your_token_hereReference that variable from your user-level ~/.npmrc:
//registry.npmjs.org/:_authToken=${NPM_TOKEN}bun run release loads .env and passes the token to npm. Never put the token
directly in a committed .npmrc or source file. If npm package settings disallow
tokens, publishing will still require an OTP. For hosted CI, prefer npm trusted
publishing instead of a long-lived token.
Keep source, tests, executable, extension, and dependencies inside this project. Keep project policies and real prompts outside it. Add automation only for concrete needs; this package has no supervisor, project registry, queue, or automatic recovery service.
