Configuration — the constitution workflow knobs¶
ArDD's behavior knobs live in constitution.md's frontmatter — they
are workflow settings, not constitution content: setting or changing one
never bumps the constitution version and never touches the Sync Impact
Report. next_step_prompt, delegation, merge_policy, and
update_check_max_age_days are stamped via ardd-state.sh stamp <file>
<field> <value>, never hand-edited; workflow_mode is written into the
frontmatter by /ardd-init directly.
Every one has a safe default when absent — projects initialized before a
field existed need no migration.
/ardd-init asks each question once at setup. By default, /ardd-update
only backfills: it asks next_step_prompt, delegation, and (solo mode)
merge_policy once for installs whose constitution lacks the field
entirely — workflow_mode is never asked by the default path and simply
defaults to solo when absent. Run /ardd-update --reconfigure to
re-ask all four fields, including workflow_mode, on demand — regardless
of whether they're already set — showing each field's current value
before asking whether to keep it or change it; this is the only way to
change workflow_mode outside of /ardd-init. Enum enforcement: the
installed lint-project.sh.
workflow_mode — where in-progress work lives¶
solo | collaborative — absent = solo.
- solo — single developer, one machine. Committing to the local
default branch is fine for inline runs;
/ardd-planhas no branch gate at all. Delegated runs use isolated worktrees that merge back eagerly and are then reaped. In-flight visibility:inflight-worktrees.sh//ardd-status's In Flight section. - collaborative — nothing is ever committed to the local default
branch. Work always moves to a branch; after the first commit the skill
offers to push and open a draft PR titled with the feature slug(s) —
the mode's shared in-flight signal. Register flips ride the branch and
land when the PR merges. Pushes always require explicit confirmation.
One extra constraint: delegated worktrees branch from
origin/<default>, so plan/tasks files must reach the remote before delegated implementation can see them.
Suggested by detection at init: branch protection on the default branch →
collaborative; no remote → solo.
next_step_prompt — one-keypress next steps¶
true | false | auto — absent = false.
When true, exactly two skills — /ardd-status and /ardd-plan — end by
offering their recommended next step via a yes/no prompt, and only when
that recommendation is a concrete runnable /ardd-* invocation (anything
else stays plain text). One prompt per user-visible turn end: when plan
hands off to status, status owns the prompt. With auto, the same
runnable recommendation is invoked directly — stated in the report text
first, no prompt; non-runnable recommendations still stay plain text. A
denied or unavailable prompt (e.g. dontAsk mode) reads as "no — stop
here", never a retry. false/absent keeps recommendations as plain text,
so delegated and scripted runs are unaffected.
delegation — the background gate¶
eager | ask | inline — absent = ask. Consulted by
/ardd-implement's delegation gate:
eager— delegate to a background worktree subagent without promptingask— offer each time, suggesting yesinline— never offer; run in the foreground
delegate_model — model routing for delegated runs¶
A single tier alias — haiku | sonnet | opus — or a comma map of
simple=<alias> / moderate=<alias> / complex=<alias> pairs (each key
optional, at least one pair, no duplicate keys; keys are the tasks-file
complexity: grades, aliases the harness model families). Examples:
complex=opus, simple=haiku,complex=opus. Absent = no routing.
Set/remove it via ardd-state.sh stamp <constitution> delegate_model
<value> / unstamp <constitution> delegate_model; grammar enforced by
lint-project.sh.
Consulted only at /ardd-implement's delegation boundary, when a worktree
subagent is dispatched — a fresh subagent context means routing there
costs no prompt cache, which is why inline runs and per-skill session
routing are deliberately not covered. Resolution rules:
- absent — no
modelparameter on theAgentcall; the subagent inherits the session model (unchanged behavior) - single alias — passed as the
Agentcall'smodel - map — the chosen tasks file's
complexity:frontmatter is read; a mapped grade passes that alias, while an unmapped grade or an absentcomplexity:field inherits. The default is asymmetric on purpose: nothing is ever routed down implicitly, and a missing grade is never guessed.
Fan-out resolves per selected tasks file, so one fan-out may dispatch to
different models. The complexity: grade itself is stamped by
/ardd-plan at tasks-file generation time (see the tasks-file
complexity: field on /ardd-plan's reference page) and corrected via
ardd-state.sh stamp <tasks-file> complexity <simple|moderate|complex>.
merge_policy — landing a delegated run¶
auto | ask — absent = ask. Solo mode only — collaborative mode
merges through the PR and never consults it (which is why init doesn't
ask it there).
auto— when a delegated run completes, merge its branch into the default branch without asking, when the merge is fast-forward or conflict-free. Any conflict aborts, surfaces, and falls back to asking — nothing is ever auto-resolved.ask— offer the merge each time, suggesting yes (eager merging keeps the in-flight window short).
plan_preview — the browser-preview question at /ardd-plan's checkpoint¶
always-browser | always-console | ask — absent = ask. Consulted
by /ardd-plan's approval checkpoint (step 10), before the three-way
approve/revise/stop question:
always-browser— skip the question; always publish the plan file via theArtifacttool and open it, then proceed to the three-way questionalways-console— skip the question; never publish, proceed straight to the three-way questionask— offer the "view in browser first?" question each time (the original, still-default behavior)
Not asked by /ardd-init or backfilled by default /ardd-update —
opt in deliberately via ardd-state.sh stamp <file> plan_preview <value>.
plan_preview_editor — the open-in-editor offer at /ardd-plan's checkpoint¶
A command template containing the literal {path} placeholder — absent
(the default) = not offered. Consulted alongside plan_preview by
/ardd-plan's approval checkpoint (step 10), before the three-way
approve/revise/stop question:
- set, with
plan_previewabsent orask— offer a yes/no "open in editor?" question; on yes, substitute the plan file's absolute path into{path}and run the resulting command - set, with
plan_previewalso set (asaskor absent) — offer a three-way question: browser / editor / no - absent — no editor offer;
plan_previewbehavior is unchanged
Example: plan_preview_editor: code {path}.
Not asked by /ardd-init or backfilled by default /ardd-update —
opt in deliberately via ardd-state.sh stamp <file> plan_preview_editor
<template>.
update_check_max_age_days — opt-in freshness fetch for the update check¶
A positive integer — absent = never fetch (the default: the update check
is local-git-only). Neither /ardd-init nor /ardd-update asks for it;
opt in deliberately:
ardd-state.sh stamp .project/artifacts/constitution.md update_check_max_age_days 7
When set, ardd-update-check.sh runs git fetch --tags on the source
before comparing — but only when the source is the release-channel owned
checkout (~/.ardd/source; a dev-mode checkout is read, never mutated,
and the self-hosted case never fetches) and the checkout's
.git/FETCH_HEAD is older than N days (missing = stale). A failed fetch
appends note=fetch-failed to the check's output line and the comparison
proceeds against local tags — offline machines lose nothing. An invalid
value behaves like absent (and is flagged by lint-project.sh).
status_history_keep — bound STATUS.md's _Updated: history¶
A positive integer — absent = unbounded (the default: /ardd-status's
prepend-and-preserve keeps the full chronology in the live file, so it
grows over time). /ardd-init asks once, and /ardd-update backfills the
question for installs whose constitution lacks the field; or set it
directly:
ardd-state.sh stamp .project/artifacts/constitution.md status_history_keep 5
When set to N, /ardd-status runs status-prune.sh <STATUS.md> --keep N
after prepending each new block, keeping only the newest N _Updated:
blocks in the file. Blocks are never summarized or rewritten — the prune
only removes whole older blocks, and the full history stays recoverable
from git (git log -p .project/STATUS.md). An invalid value behaves like
absent — the prune is skipped and /ardd-status notes the invalid value in its report — and is flagged by lint-project.sh (valid = a positive integer of at most 4 digits).
ARDD_VERSION_BADGE — dynamic version badge (install-time env, not frontmatter)¶
ARDD_VERSION_BADGE=1 ./install.sh <project> opts a target into the
dynamic ArDD version badge: install.sh writes
.github/workflows/ardd-badge.yml, a seeded
.github/badges/ardd-version.json, and the badge mark
.github/badges/ardd-icon.svg (copied from the source's
templates/ardd-icon.svg), then prints the README snippet. Public repos
only — shields.io fetches raw.githubusercontent.com unauthenticated.
The ArDD brand colour is #2F4858. The badge JSON carries it as
labelColor (the badge's left half), while color (the right half)
stays the channel signal: blue = stable, yellow = beta. The JSON also
inlines the icon as logoSvg, so brand colour and mark propagate to
consumer badges through the sync workflow — no README re-editing when
either changes upstream. The printed snippet is the split badge — one
endpoint badge reading "built with ArDD │ vX.Y.Z" whose JSON supplies
both halves; templates/badge.md documents all three shapes
(static-only, split, two-badge pair) and the renderer caveats.
shieldcn.dev is the default badge offer; shields.io is the fallback.
install.sh detects whether the target README already carries a
pre-existing, non-ArDD img.shields.io badge outside ArDD's own marker
blocks (EXISTING_SHIELDS_IO). If it doesn't, every print site (both the
static-only snippet and the ARDD_VERSION_BADGE=1 split snippet) offers
the shieldcn.dev-rendered form from templates/badge-shieldcn.md — ArDD's
own README uses shieldcn badges, so that's the house style. If the target
already has a non-ArDD shields.io badge, install.sh falls back to
templates/badge.md's shields.io form instead, matching the target's
existing visual language rather than introducing a second one. Both
templates ship in the ArDD source regardless of which one a given run
selects; the printed advisory also invites hand-adapting the offered
snippet's variant/theme (shieldcn) or colour (shields.io) query
params to whatever styling is already visible in the target README.
Using a different badge system entirely? Submit a new template design
upstream to the ArDD repo (templates/) rather than hand-rolling one.
Related per-clone git opt-ins (not frontmatter)¶
Two settings git refuses to take from a repo commit, suggested by install.sh and set once per clone:
git config merge.ours.driver true # report files merge clean, keeping the current side
(and in this source repo only, git config core.hooksPath hooks for the
pre-commit checks — see CONTRIBUTING.md.)