archdev.json reference
Every archdev.json setting, the three config files and their precedence, and how pipelines execute.
ArchDev reads repository configuration from archdev.json. This page lists every supported key, which file each key belongs in, how the files merge, and how the pipeline system executes.
Config files
Three files merge into the effective configuration. Checked-in files own repository policy; personal files own model and provider choice.
| File | Path | Committed | Owns |
|---|---|---|---|
| Project | <repo>/archdev.json |
Yes | Repository policy: pipelines, bindings, review, factory policy, publish, worktree, tasks |
| User | ~/.archdev/archdev.json |
No (mode 0600) |
Personal model and provider choice |
| Local overlay | <repo>/archdev.local.json |
No (gitignored) | Per-checkout experiment overrides |
Validate the merged result without executing anything:
archdev check
archdev check parses every pipeline, resolves every binding, compiles every workflow, and verifies every model selector. It prints a table, or JSON in JSON mode. Fix what it reports before pushing config changes.
Minimal example
{
"app": "current",
"review": { "default_workflow": "team-review" },
"factory": { "workers": 10, "model": "@factory-automation" },
"modelAliases": {
"factory-automation": [
{ "provider": "openai", "model": "gpt-5.6-sol" },
{ "provider": "platform", "model": "openai/gpt-5.6-sol" }
]
},
"publish": { "auto": true, "model": "@publication-metadata" },
"pipelines": {
"branch-validation": {
"steps": [
{
"id": "lint",
"run": ["aster", "affected", "lint", "--base", "origin/main"],
"timeout_seconds": 900,
"continue_on_error": true
},
{ "id": "review", "uses": "review-and-fix" }
]
}
},
"pipeline_bindings": { "branch_update": "branch-validation" }
}
Layering and precedence
Objects merge per field; scalar values are winner-takes-all. The general rule is project policy wins, personal model choice wins:
- For
pipelines,review,factory,daemon,publish, andtasks, fields set inarchdev.jsonbeat the same fields in the user file and the local overlay. - These model selections always come from the personal side (user file, then local overlay): the root
modelAliasesmap,factory.model,factory.worker_model,publish.model, and the fourevalsmodel fields. Set a model in your user file once and no repository edit can override it. modelProvidersaccount selection is always user-owned.tasksis repository policy, but the gitignored local overlay applies last, so it works as a per-checkout experiment override.pull_requests.automation.pause_labelresolves last-set-wins across user, local, then project files.- The user file can never set
app,local, orworktree. Repository identity and worktree hooks only come from checked-in or daemon-managed files. - Exact-commit daemon paths merge without the local overlay, so uncommitted local edits cannot change an already-queued job.
Top-level keys
All keys are optional. An absent key means its default, never null.
| Key | Type | Default |
|---|---|---|
app |
"current" or app id |
none; written by setup |
api_url, portal_url |
HTTP(S) URL | https://platform.archastro.ai, https://archdev.ai |
auth_mode |
"developer", "org" |
"developer" |
sandbox |
non-empty string | none |
modelAliases |
map of alias to model ref or ref list | {} |
review |
object | {} |
factory |
object | {} |
publish |
object | {} |
pipelines |
map of name to { steps } |
{} plus built-ins |
pipeline_bindings |
map of trigger to pipeline name | built-in bindings |
worktree |
object | { hooks: {} } |
daemon |
object | {} |
tasks |
object | { backend: "archdev" } |
pull_requests |
object | { automation: { pause_label: "no-autofix" } } |
evals |
object | see Evals |
local |
object | none; daemon-managed, do not edit by hand |
api_url and portal_url can also be set with ARCHDEV_API_URL and ARCHDEV_PORTAL_URL. The legacy singular pipeline key is rejected: define pipelines under pipelines and bind them under pipeline_bindings.
Identity and connection
| Key | Type | Default | Notes |
|---|---|---|---|
app |
"current" or dap_ id |
none | Repository identity. Must be "current" or match dap_ plus letters, numbers, _, -. |
api_url |
HTTP(S) URL string | https://platform.archastro.ai |
Must parse as http: or https:. |
portal_url |
HTTP(S) URL string | https://archdev.ai |
Same URL rule. |
auth_mode |
"developer", "org" |
"developer" |
Which login flow the CLI uses. |
sandbox |
non-empty string | none | Sandbox selection for runs. |
modelAliases
Aliases give a short name to an ordered fallback list of models. Model fields elsewhere reference them as "@alias-name". Alias names must match ^[a-z][a-z0-9._-]{0,63}$. Each entry is one { provider, model } object or a non-empty array of them, tried in order.
"modelAliases": {
"factory-automation": [
{ "provider": "openai", "model": "gpt-5.6-sol" },
{ "provider": "xai", "model": "grok-4.6" },
{ "provider": "platform", "model": "openai/gpt-5.6-sol" }
]
}
A provider of "platform" routes through your ArchDev model access with a provider/model id; other providers use that provider directly. An invalid alias entry fails archdev check with modelAliases.<name> must be a valid model reference or non-empty fallback list. The fallback default model is platform/xai/grok-latest-thinking-high.
review
| Key | Type | Default | Notes |
|---|---|---|---|
review.default_workflow |
non-empty string | "default" |
Named review workflow run over branch commits. Must name a workflow that exists, or archdev check fails with Unknown default review workflow. |
Named workflows and review workflows are files, not inline config. The loader reads project <repo>/.archdev/workflows and user ~/.archdev/workflows; built-ins cover default. The example at the top of this page selects the team-review workflow.
factory
Controls the overseer/worker orchestration: how many workers, who claims work, and which models drive each role. CLI flags beat config: --dispatch beats factory.dispatch, --autonomy beats factory.autonomy, --model beats factory.model, and --workers beats factory.workers.
| Key | Type | Default |
|---|---|---|
factory.workers |
integer 1–32 | 3 |
factory.dispatch |
"auto", "manual" |
"auto" |
factory.autonomy |
"confirm", "auto" |
"confirm" |
factory.overseer_instructions |
non-empty string | none |
factory.worker_instructions |
non-empty string | none |
factory.model |
model selector string or array | platform/xai/grok-latest-thinking-high |
factory.worker_model |
model selector string or array | follows the live overseer model |
factory.one_off_workers |
"confirm", "auto", "disabled" |
"confirm" |
Details:
dispatch: "auto"claims every ready task;"manual"claims only user-released tasks.autonomy: "confirm"asks before consequential worker actions;"auto"proceeds without asking.overseer_instructionsandworker_instructionsare free-text prompts prepended to each role.- A model selector is a literal
provider/modelstring, a@aliasreference, or an array of selectors tried in order.factory.worker_modelpins workers when set; otherwise workers follow the live overseer model, includingfactory.model. - Unknown
factorykeys are ignored, so a typo there will not fail validation. Preferarchdev checkplus a careful re-read when factory behavior surprises you.
publish
| Key | Type | Default |
|---|---|---|
publish.auto |
boolean | true while the built-in branch-validation pipeline handles branch updates, else false |
publish.base |
non-empty string | "main" |
publish.remote |
non-empty string | "origin" |
publish.model |
model selector string or array | none (falls back to the default model) |
Constraints: automatic publication requires publish.remote to be "origin". The built-in branch-validation pipeline additionally requires publish.base "main"; point branch_update at a custom pipeline to use another base or remote.
pipelines
pipelines maps a name to { steps: [...] }. Names match step-id syntax. Run one locally with archdev pipeline run <name> in the current worktree.
Step fields
Each step is either a command step (run) or a pipeline call (uses), never both. A call step may only set id and uses.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
string, ^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$ |
required | Unique within the pipeline. archdev-auto-publish and archdev-verify-lineage are reserved. |
run |
non-empty array of non-empty strings | required unless uses |
argv executed for the step. |
uses |
pipeline name | — | Inlines another pipeline's steps. Cannot combine with run, cwd, env, timeout_seconds, or continue_on_error. |
cwd |
relative path | "." |
Working directory for run. Must stay inside the pipeline worktree; absolute paths and .. escapes are rejected. |
env |
map of string to string | {} |
Extra environment for the step. Keys must match ^[A-Za-z_][A-Za-z0-9_]*$ and must not start with ARCHDEV_, which is reserved for pipeline variables below. |
timeout_seconds |
integer 1–86400 | none (unbounded but cancellable) | A step with a timeout is killed when it expires; without one it runs until it finishes or is cancelled. |
continue_on_error |
boolean | false |
On true, a failed step is recorded as failed_continued and the pipeline keeps going. Cancellation and timeouts are always terminal. |
Composition with uses
uses is a compile-time call, expanded before anything runs:
- The called pipeline's steps are inlined with dotted ids prefixed by the caller (
review.fix,review.commit), so evidence and logs stay unambiguous. - Cycles are rejected (
Pipeline cycle: a -> b -> a). - The fully expanded pipeline may contain at most 100 commands.
"pipelines": {
"branch-validation": {
"steps": [
{ "id": "lint", "run": ["aster", "affected", "lint", "--base", "origin/main"], "continue_on_error": true },
{ "id": "review", "uses": "review-and-fix" }
]
}
}
Built-in pipelines
These exist without any configuration; defining the same name in pipelines overrides the built-in:
| Name | What it does |
|---|---|
branch-validation |
Runs the configured review workflow over branch commits, then an agent fixes supported findings and commits. |
address-pull-request-feedback |
Agent addresses newly failed CI checks and review comments on the frozen PR head, then the host-owned finalizer publishes. |
resolve-pull-request-rebase-conflict |
Agent rebases the PR onto the frozen base target and verifies the replay, then the finalizer publishes. |
resolve-branch-rebase-conflict |
Agent rebases a retained branch checkout onto the exact base commit for daemon compare-and-swap resume. |
one-off |
Ad-hoc single-prompt runs (16 KiB prompt cap). |
pipeline_bindings
Bindings connect daemon triggers to pipelines. A binding value must name a pipeline that parses; an unknown name fails validation.
| Trigger | Default pipeline | Fires when |
|---|---|---|
branch_update |
branch-validation |
Branch commits change and need validation. |
pull_request_feedback |
address-pull-request-feedback |
New CI failures or review comments arrive on a tracked PR. |
pull_request_rebase_conflict |
resolve-pull-request-rebase-conflict |
A tracked PR can no longer be rebased onto its base. |
branch_rebase_conflict |
resolve-branch-rebase-conflict |
A retained branch checkout conflicts with its base. |
Omit pipeline_bindings (or a single trigger) to keep the default. To disable automation for a trigger, point it at a pipeline whose steps exit cleanly without doing work.
worktree
Hooks and environment for daemon-managed worktrees. Unknown keys anywhere under worktree are rejected, unlike factory.
| Key | Shape | Retries |
|---|---|---|
worktree.hooks.after_worktree_create |
{ run, timeout_seconds?, retry? } |
allowed |
worktree.hooks.after_worktree_delete |
{ run, timeout_seconds? } |
not allowed |
worktree.runtime_environment |
{ run, timeout_seconds? } |
not allowed |
run is a non-empty array of non-empty strings. timeout_seconds is an integer from 1 to 86400. The create hook runs after a worktree is prepared (up to 1800 seconds in the example at the top of the repo config); the delete hook runs on cleanup. runtime_environment probes the worktree runtime before use.
daemon
| Key | Type | Default | Notes |
|---|---|---|---|
daemon.pr_tracking_scope |
"all-authored", "factory-only" |
daemon default | Which PRs the daemon tracks. Lives in the user file and is written by CLI commands; rarely set by hand. |
tasks
Selects the task backend the factory claims work from. Repository policy, with the local overlay applied last. ARCHDEV_TASKS_BACKEND overrides the merged value.
| Key | Type | Default | Notes |
|---|---|---|---|
tasks.backend |
"archdev", "beads", "github" |
"archdev" |
Unknown tasks.* keys are rejected. |
tasks.beads.dir |
non-empty string | none | Directory for the beads backend. |
tasks.github.repo |
"owner/repo" |
none | Required when backend is "github". |
pull_requests
| Key | Type | Default | Notes |
|---|---|---|---|
pull_requests.automation.pause_label |
non-empty string | "no-autofix" |
Label that pauses PR automation. Last set wins across user, local, then project files. |
evals
Agent evaluation harness settings. Every source is validated before merging.
| Key | Type | Default |
|---|---|---|
evals.directory |
string | ".archdev/evals" |
evals.model |
model selector string or array | platform/xai/grok-latest-thinking-high |
evals.author_model |
model selector string or array | none |
evals.judge_model |
model selector string or array | none |
evals.mock_model |
model selector string or array | none |
evals.runs |
number | 3 |
evals.concurrency |
number | 1 |
evals.max_turns |
number | 30 |
evals.timeout_seconds |
number | 600 |
local
local holds daemon-managed repository identity (project_id, repo_name, plus debug_projects scopes for non-production installs). It is stripped from the user file on merge. Do not edit it by hand; setup and the daemon maintain it.
How pipelines run
Whether triggered by the daemon or started by hand with archdev pipeline run <name>, execution follows one model:
- Parse and expand. The named pipeline is parsed,
usescalls are inlined with dotted step ids, and the result is capped at 100 commands. Anything invalid fails before any step runs. - Sequential steps. Steps run in order, each in
cwdinside the pipeline worktree. The first failure stops the pipeline unless that step setscontinue_on_error, which recordsfailed_continuedand continues. Cancellation and timeouts always stop the run. - Output chaining. Each step's stdout is saved and handed to the next step twice: piped on stdin and as a file path in
ARCHDEV_PREVIOUS_OUTPUT. A step reads the previous result instead of re-deriving it. - Evidence file.
ARCHDEV_PIPELINE_EVIDENCEpoints at a JSON record rewritten after every step with the ordered step history: ids, commands, states, exits, and output tails. Later steps (and the review-and-fix prompts) read lint failures and findings from evidence rather than re-running earlier steps.
Step environment
On top of env and the usual shell environment, every step receives:
| Variable | Contents |
|---|---|
ARCHDEV_JOB_ID |
Job id, or "local" for manual runs |
ARCHDEV_STEP_ID |
Current step id |
ARCHDEV_PROJECT_ID |
Repository identity when known |
ARCHDEV_REF, ARCHDEV_BRANCH, ARCHDEV_COMMIT |
Git position of the worktree |
ARCHDEV_WORKTREE |
Absolute worktree path |
ARCHDEV_ATTEMPT |
Attempt number |
ARCHDEV_STEP_RESULT, ARCHDEV_STEP_STDOUT, ARCHDEV_STEP_STDERR |
Paths for the step's result and captured streams |
ARCHDEV_PREVIOUS_OUTPUT |
Previous step's stdout path (set from the second step on) |
ARCHDEV_PIPELINE_EVIDENCE |
Cumulative evidence JSON path (always set) |
Custom env keys must not start with ARCHDEV_; the runner rejects them so user config cannot spoof pipeline variables.