Skip to content

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-plan has 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 prompting
  • ask — offer each time, suggesting yes
  • inline — 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 model parameter on the Agent call; the subagent inherits the session model (unchanged behavior)
  • single alias — passed as the Agent call's model
  • map — the chosen tasks file's complexity: frontmatter is read; a mapped grade passes that alias, while an unmapped grade or an absent complexity: 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 the Artifact tool and open it, then proceed to the three-way question
  • always-console — skip the question; never publish, proceed straight to the three-way question
  • ask — 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_preview absent or ask — 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_preview also set (as ask or absent) — offer a three-way question: browser / editor / no
  • absent — no editor offer; plan_preview behavior 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.

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.)