Skip to content

Latest commit

 

History

History
268 lines (214 loc) · 13.8 KB

reference.md

File metadata and controls

268 lines (214 loc) · 13.8 KB

Configuration and CLI reference

Everything a host repo can configure, and every command the stages run. The stage contracts themselves live in the skill pages; this page covers the plumbing around them.

Running the commands

The skills call the mechanized gates as damascus <cmd>. That means the damascus checkout's install.sh <cmd>, which hands off to scripts/damascus-<cmd> (or evals/run_eval.py for eval):

vendor/damascus/install.sh agent-run --probe     # from a consumer repo root
./install.sh eval                                # inside damascus itself

No global damascus command is installed. Every command is Python 3.9+ standard library only and takes --help; the gates work on the repository in the current directory unless given --repo.

agent-run: routing critics, judge and implementer

damascus agent-run sends one prompt to one model and prints the reply. Temper and hone use it when you want critics or the judge on a different model than the session's own subagents; it is never required.

damascus agent-run --probe                                   # JSON: reachable servers, Ollama models, agent CLIs
damascus agent-run --role critic-a --input-file bundle.md   # route by role (see below)
damascus agent-run --backend ollama --model <name> --prompt "..."
Flag Meaning
--backend auto (default), local-openai, ollama, claude, gemini, codex, opencode, llm, rule-auditor, custom
--role critic-a … critic-d, judge, implementer, generic; selects routing keys and labels critic output ### CRITIC A …
--model model name for the chosen backend
--prompt / --input-file the user prompt, inline or from a file
--system / --system-file an optional system prompt
--output-file also write the reply to a file
--temperature, --max-tokens, --num-ctx sampling, output length for HTTP backends, Ollama context (default 32768)
--timeout seconds before the backend call is abandoned (default 300)
--no-strip-identity keep model/provider self-identification (stripped by default so the judge rates blind)
--no-fallback exit 3 instead of falling back to the rule-auditor (see below)

Backends. local-openai talks to any OpenAI-compatible server — llama.cpp's llama-server, vLLM, SGLang, LM Studio, LocalAI. ollama uses Ollama's API. claude, gemini, codex, opencode and llm run that agent CLI non-interactively. custom pipes the prompt into the command in DAMASCUS_CUSTOM_CMD. rule-auditor is the built-in deterministic checker described below.

auto first applies the routing below. If that names no backend, it uses the first of: a reachable OpenAI-compatible server (DAMASCUS_LOCAL_URL or OPENAI_BASE_URL, else 127.0.0.1 ports 8080, 8000 and 1234), Ollama with at least one model pulled, then an installed agent CLI — with two or more CLIs installed, critic-a, critic-b and critic-c each get a different one, for diversity. When nothing answers — nothing found, a CLI failed, timed out or printed nothing — it falls back to the rule-auditor and says so: a [WARN] on stderr and a > rule-auditor fallback line in the output. The rule-auditor runs regex checks for a few known defect patterns; its output is not a model review. Pass --no-fallback when you need a model's answer or nothing.

Role routing: .damascus/models.conf

When no --model is given, the model comes from the first match in the right-hand column; when --backend is auto (the default), the backend comes from the first match in the left-hand column. The <ROLE> rows apply only with --role, which is upper-cased with dashes turned into underscores (critic-a → CRITIC_A):

Backend from Model from
env DAMASCUS_<ROLE>_BACKEND env DAMASCUS_<ROLE>_MODEL
models.conf <ROLE>_BACKEND models.conf <ROLE>_MODEL
env DAMASCUS_BACKEND env DAMASCUS_MODEL
models.conf DEFAULT_BACKEND models.conf DEFAULT_MODEL

An explicit --backend or --model on the command line wins over its column. models.conf is read from .damascus/models.conf under the current directory, as KEY=VALUE lines; # starts a comment and surrounding quotes are dropped:

# .damascus/models.conf — critics on a local server, the judge on another agent CLI
DEFAULT_BACKEND=local-openai
DEFAULT_MODEL=<your-local-model>
JUDGE_BACKEND=<agent-cli>
CRITIC_C_BACKEND=ollama
CRITIC_C_MODEL=<an-ollama-model>

LOCAL_OPENAI_URL in the file sets the server URL when no environment variable does. Without a model name, local-openai uses the first model the server lists and ollama the first model Ollama has pulled, else OLLAMA_MODEL; with none of these, an Ollama call stops with an error rather than guessing a model.

Environment variables

Variable Used for
DAMASCUS_LOCAL_URL, OPENAI_BASE_URL the OpenAI-compatible server's base URL (e.g. http://127.0.0.1:8080/v1)
DAMASCUS_API_KEY, OPENAI_API_KEY that server's API key, if it needs one
OLLAMA_HOST Ollama's URL (default http://127.0.0.1:11434)
OLLAMA_MODEL the Ollama model to use when none is configured and Ollama lists none
DAMASCUS_CUSTOM_CMD the command line for --backend custom; it receives the prompt on stdin
DAMASCUS_<ROLE>_BACKEND, DAMASCUS_<ROLE>_MODEL, DAMASCUS_BACKEND, DAMASCUS_MODEL routing overrides (table above)

Mechanized gates

Each gate exits 0 when it passes and 1 when it doesn't, so a stage can't report green over a failed gate.

test-lock

Freezes tests at amber and checks them at green (quench's test-freeze rule).

damascus test-lock lock --task T001 [--path tests/unit/test_x.py]   # record SHA-256 of the task's tests
damascus test-lock verify [--allow-new]                             # fail on any edit or deletion since lock
damascus test-lock unlock --reason "AMBER-AMEND: spec FR-003 changed" # spec changed first; relock afterwards

Without --path, lock takes every file under tests/, test/ and e2e/. The manifest is .damascus/locks/amber-tests.sha256.json (--lock-file to move it). --allow-new lets new test files appear while the locked ones stay frozen.

bdd-check

Fails when a .feature file has no Scenario, or no test file binds it (pytest-bdd scenarios("…") or @scenario(…)) — the case where pytest exits 0 having run none of its scenarios. Features are found under tests/, features/ and e2e/ unless --feature-dir names a directory or file.

revert-proof

Shows a fix fails without itself. For each case it checks out the fixed commit in a throwaway worktree, confirms the test passes, reverts only the production files to the base ref, reruns the test and classifies the result:

Result Meaning
RED — pass the test ran and failed on its assertion (matching expected_regex if given)
GREEN — fail the test still passes without the fix: it doesn't test the fix
INCONCLUSIVE — fail the run broke before the assertion (import, collection or syntax error)

One case from flags, or many from a file:

damascus revert-proof --id F1 --base-ref HEAD~1 --prod-file src/app/discounts.py \
  --test-cmd "pytest tests/unit/test_discounts.py -q" --expect-regex "AssertionError"
damascus revert-proof --cases specs/001-x/cases.json --report-out specs/001-x/revert-proof.json
{"cases": [
  {"id": "F1", "base_ref": "HEAD~1", "fix_ref": "HEAD",
   "production_files": ["src/app/discounts.py"],
   "test_cmd": "pytest tests/unit/test_discounts.py -q",
   "expected_regex": "AssertionError"}
]}

A bare list of cases works too. --timeout bounds each test run (default 180 s).

proof-coverage

Fails when any production file changed between --base-ref and --fix-ref (default HEAD) has no RED revert-proof in --report (the --report-out file above). Paths under tests/, test/, specs/, docs/, .prd/ and the harness directories are exempt; --exempt-glob adds patterns, and an "exemptions" object in the report ({"path": "reason"}) exempts a file with a stated reason.

damascus proof-coverage --base-ref HEAD~3 --report specs/001-x/revert-proof.json

upgrade-consumers

Reports on, and re-links, other repos that use damascus: for each one it runs that repo's own vendor/damascus/install.sh --all-harnesses and then --verify, so its links keep pointing at its own pinned submodule. It does not move anyone's pin — bump that first. Read-only checkouts are reported and skipped, and so is a repo without vendor/damascus (SKIPPED_NO_VENDOR). It exits 1 if any install or verify failed.

damascus upgrade-consumers --scan-dir ~/src --check     # report only: harnesses, pinned commit, writability
damascus upgrade-consumers --repo ../shop-api           # re-link one repo (repeatable)

--link-to-this-checkout links a repo that has no vendor/damascus to the checkout running the command instead; those links leave the repo, so a fresh clone of it won't have them. --dry-run passes --dry-run to each install, --claude-only links .claude/ only, and --json prints a machine-readable report.

Stage addenda: .damascus/addenda/<stage>.md

A host repo can extend a stage without forking it. Each stage reads its addendum, when present, before it starts:

File Read by Typical content
forge.md forge extra domain questions folded into the REASONS Canvas
anvil.md anvil decomposition constraints (e.g. every task names its migration)
temper.md temper domain checks for the critics, or a fourth lens critic-d
quench.md quench extra test or build gates a task must pass at green
hone.md hone domain checks for the critics, or a fourth lens critic-d

Addenda are plain Markdown instructions that the stage applies alongside its own; the skill pages say exactly where each one is read.

Experience: .damascus/experience.md

Addenda hold rules that apply to every feature. Experience holds lessons that apply only when a feature looks like an earlier one. Smithy's finish step writes it: after a feature completes, it reads the feature's trail and appends at most one entry, usually none. Each stage reads the entries whose Stage names it, next to its addendum, and applies those whose Cue matches the work in front of it.

## NNN-<slug> — <short title>
- Stage: anvil
- Cue: <the feature shape or symptom that makes it apply>
- Lesson: <what that stage does differently when the cue matches>
- Evidence: <artifact path and the round, task or entry that shows it>
- Confidence: <high | medium | low>

An entry without a cue, a lesson, and evidence in its feature's trail is refused. Cue and lesson carry no ratings, because temper and hone pass them to critics who must stay blind to earlier rounds; evidence stays out of the critics' bundle. A lesson that holds for every feature is proposed as an addendum line instead. The file is the host repo's own: commit it, and edit, merge or delete entries by hand when they stop paying for their context. The contract follows the experience records of Harness², which refuses a lesson without a cue and evidence. The worked example records one.

Evaluation harness: eval

damascus eval scores damascus itself; it is for working on this repo, not on a consumer.

./install.sh eval                                   # J_damascus, 0–100; exits 1 below 95
./install.sh eval --json --record                   # JSON report; append a row to evals/results.tsv
./install.sh eval --live-llm --backend <backend>    # also benchmark a real critic model
./install.sh eval --live-llm --backend <backend> --runs 3 --critic-timeout 300   # repeat; report the spread
./install.sh eval --check-corpus                    # self-check the live benchmark's scorer and corpus

J_damascus adds up four deterministic components: the smoke test (25), the mechanized gates against seeded defects (35), protocol and model-agnosticism invariants (25) and a prompt-size budget (15: agents ≤ 150 lines, stage skills ≤ 260). CI fails below 95. evals/program.md is the keep/revert protocol for improving the skills against it.

The live benchmark (--live-llm) is a separate number. It sends every case in evals/corpus/seeded_cases.json — seeded specs and diffs plus a clean control — to the backend as a temper or hone critic. A seeded defect counts as found only when a [BLOCKING] finding names it and says what is wrong in words that don't occur in the prompt, so a model that echoes its input scores 0. The report gives recall, blocking findings on the clean control (false positives), the echo baseline, and any case where the backend failed. Every prompt and raw reply is saved under .damascus/eval-runs/<time>-<backend>/ (--out-dir to override) so a score can be checked by hand. Replies vary from run to run, so --runs N repeats the corpus and reports recall per run, its mean and range, and how often each defect was found; --critic-timeout (default 170 s) bounds each critic call, and a call that runs out is reported as an errored case, not a clean one. The scorer's term lists are still being tuned; a term added after reading replies must come from a backend other than the one being reported. A --backend rule-auditor run scores the regex checker, whose patterns were written against this corpus, so its result says nothing about models.