Configuration
Settings decide how each stage runs: who commits, which browser, how much model. They never decide whether a stage runs.
Modes, never gates. No setting can skip the plan approval, the review, the manual test or your confirmation before a commit. Ask to turn one off and the agent will say no.
How to change a setting
Say it in plain words. The agent names the key and the file, shows the diff, and writes only after your yes.
Use implementator. Turn on CI watching for tally/cli.
What does tally/cli use for pull requests?
Use the team preset for all projects.
Where a value comes from
- The project:
projects/<product>/<id>/project.json.
- Your defaults:
implementator.json at the notes root.
- Built in: the defaults on this page.
The first one that sets a key wins. A project overrides your defaults one key at a time, so it never has to repeat a whole block.
{
"version": 1,
"defaults": {
"features": {
"git": { "pr": "ready" },
"selfTest": { "maxIterations": 3 }
}
}
}
Presets
A preset is a named set of settings. It goes through the same diff and the same yes as any other change.
| Preset | What it sets up |
|---|
backend-api | A service with no screens: the self-test calls the live API over HTTP and no screenshots are taken. Apply it to that component, not to defaults. |
headless-ci | No browser windows while it works: Playwright runs headless, CI is watched after the push, and one visible drive at the end shows you the result. |
routing-economical | Lower model cost: mechanical stages and coding on the cheap tier, the reasoning gates (plan, triage, review) at their floor of standard. A stage that stalls is re-run once on strong before its result is trusted. |
routing-max-quality | Highest quality, highest cost: coding, the self-test and the reasoning gates all on the strong tier at high effort. |
solo | One person, no review queue: the agent commits and pushes after your confirmation, and opens no pull request. |
team | A shared repo: each workstream in its own worktree, a draft pull request, and CI watched until it is green. |
thorough-evidence | More proof per change: a smoke pass over the core flows, screenshots on every UI change at three sizes and in dark mode, and a recording of any drive that fails. Recording needs the Playwright MCP server started with --caps=devtools. |
you-commit | You keep the keyboard on git: the agent stages the change and prints the commit message; you commit, push and open the PR. |
Every setting
How finished work leaves
features.git.commit
Who runs git commit in your code repo. agent commits after you confirm. user stages the change and prints the message, and you take it from there.
Change it when: you want to keep your hands on every commit.
- Values
agent user- Default
agent- Applies to
- all projects, or one
{"features": {"git": {"commit": "agent"}}}
features.git.push
Whether the agent pushes. false commits locally only.
Change it when: the repo has no remote yet, or you push by hand.
- Values
true false- Default
true- Applies to
- all projects, or one
{"features": {"git": {"push": true}}}
features.git.pr
How a pull request is opened: as a draft, ready for review, or not at all.
Change it when: you work alone (never) or your team reviews straight away (ready).
- Values
draft ready never- Default
draft- Applies to
- all projects, or one
{"features": {"git": {"pr": "draft"}}}
features.git.branchPrefix
A prefix for branches the loop creates, such as feat/. Left unset, it follows the repo's own convention.
Change it when: your team has a naming rule the repo does not show.
- Values
- text
- Default
- not set
- Applies to
- all projects, or one
{"features": {"git": {"branchPrefix": "..."}}}
features.git.worktree
Does each workstream's code changes in its own git worktree, so your main checkout stays untouched.
Change it when: you run several sessions on one repo.
- Values
true false- Default
false- Applies to
- all projects, or one
{"features": {"git": {"worktree": false}}}
After a push
features.postPush.watchCI
Watches CI after a push through the host's own CLI and fixes what goes red. It checks for a merge conflict first, because a conflict stops CI from running at all.
Change it when: the repo has CI and the host CLI is signed in.
- Values
true false- Default
false- Applies to
- all projects, or one
{"features": {"postPush": {"watchCI": false}}}
features.postPush.finalHeadedTest
Runs one last drive of the changed screens in a visible browser, once CI is green.
Change it when: you want a final look at the real thing before merging.
- Values
true false- Default
false- Applies to
- all projects, or one
{"features": {"postPush": {"finalHeadedTest": false}}}
features.postPush.flakePatterns
Patterns for failures you know to be flaky. A match is labelled as a known flake and the rerun command is suggested. Nothing is rerun by itself, and an unmatched failure still counts as a real one.
Change it when: one CI job fails at random and wastes your time.
- Values
- a list
- Default
- not set
- Applies to
- all projects, or one
{"features": {"postPush": {"flakePatterns": "..."}}}
platform.host
Where the code is hosted, which decides the CLI used for pull requests. auto reads it from the repo's origin remote.
Change it when: the remote's address does not show the host, such as a self-hosted server.
- Values
auto github gitlab bitbucket azure-devops gitea other none- Default
auto- Applies to
- all projects, or one
{"platform": {"host": "auto"}}
platform.tracker
The issue tracker your ticket ids come from. none leaves ids as plain text.
Change it when: your branch or initiative names carry ids like ABC-123.
- Values
none linear jira github gitlab azure-boards other- Default
none- Applies to
- all projects, or one
{"platform": {"tracker": "none"}}
platform.ticketPattern
A regular expression for your ticket ids, such as ACME-\d+.
Change it when: your ids do not look like ABC-123.
- Values
- text
- Default
- not set
- Applies to
- all projects, or one
{"platform": {"ticketPattern": "..."}}
platform.ticketUrl
The address of a ticket, with {id} where the id goes.
Change it when: you set a tracker and want ids turned into links.
- Values
- text
- Default
- not set
- Applies to
- all projects, or one
{"platform": {"ticketUrl": "..."}}
How a change is verified
verification
How the agent drives a change itself. browser uses a real browser, api calls a live server, mobile uses a device or emulator, generic runs the real command. auto picks from the project type.
Change it when: the type of a project does not match how it is really used.
- Values
browser api mobile generic auto- Default
auto- Applies to
- all projects, or one
{"verification": "auto"}
features.selfTest.unhappyPaths
Which failure paths the self-test must force besides the happy path.
Change it when: a path does not exist on a surface, such as no loading state.
- Values
- a list
- Default
["error", "loading", "empty"]- Applies to
- all projects, or one
{"features": {"selfTest": {"unhappyPaths": ["error", "loading", "empty"]}}}
features.selfTest.maxIterations
How many fix-and-retry rounds the self-test gets before it reports the result as flaky instead of guessing.
Change it when: a slow project burns too much on retries.
- Values
- a whole number
- Default
5- Applies to
- all projects, or one
{"features": {"selfTest": {"maxIterations": 5}}}
features.selfTest.smokePass
Adds a short drive over the app's core flows, not only the screens that changed.
Change it when: changes tend to break things far from where they were made.
- Values
true false- Default
false- Applies to
- all projects, or one
{"features": {"selfTest": {"smokePass": false}}}
features.selfTest.record
Records the browser self-test as evidence: video, trace, both, or only when something goes wrong. Needs a Playwright MCP server started with --caps=devtools.
Change it when: you want proof of a drive to attach to a review.
- Values
off video trace both on-failure- Default
off- Applies to
- all projects, or one
{"features": {"selfTest": {"record": "off"}}}
tests.unit
Whether the loop writes unit tests. false writes no new ones, and the existing suite still runs.
Change it when: a project has no unit test setup and should not get one.
- Values
true false- Default
- not set
- Applies to
- each project
{"tests": {"unit": "..."}}
testHooks
The attribute the self-test finds elements by, such as data-testid.
Change it when: the project uses something other than what the scan found.
- Values
- text
- Default
- not set
- Applies to
- each project
{"testHooks": "..."}
Browser and screenshots
features.browserDriver
What drives the browser self-test. auto uses the Playwright MCP server when connected. claude-chrome is for Claude Code only, with the Claude in Chrome extension.
Change it when: you need your real, signed-in Chrome.
- Values
auto claude-chrome playwright- Default
auto- Applies to
- all projects, or one
{"features": {"browserDriver": "auto"}}
features.browserMode
Whether Playwright shows a window. Set when the server starts, so a session cannot change it midway. The loop looks for an MCP server named playwright for headed runs and playwright-headless for headless ones.
Change it when: you run on a server or want to keep working undisturbed.
- Values
headed headless- Default
headed- Applies to
- all projects, or one
{"features": {"browserMode": "headed"}}
features.screenshots.mode
When pull request screenshots are taken. auto takes them only if a change alters something visible.
Change it when: you want them always, or never.
- Values
auto always never- Default
auto- Applies to
- all projects, or one
{"features": {"screenshots": {"mode": "auto"}}}
features.screenshots.viewports
Which sizes to capture: desktop, tablet, mobile.
Change it when: the project has a phone layout worth showing.
- Values
- a list
- Default
["desktop"]- Applies to
- all projects, or one
{"features": {"screenshots": {"viewports": ["desktop"]}}}
features.screenshots.darkMode
Also captures each shot in the dark colour scheme.
Change it when: the app has a dark mode.
- Values
true false- Default
false- Applies to
- all projects, or one
{"features": {"screenshots": {"darkMode": false}}}
Project rules and review format
rules
A path to a Markdown file of hard rules for this project, which the loop must honour.
Change it when: something must always hold, such as "no new dependencies".
- Values
- text
- Default
- not set
- Applies to
- each project
{"rules": "..."}
review.reportFormat
A path to your own template for the review report.
Change it when: your team expects a set format.
- Values
- text
- Default
- not set
- Applies to
- each project
{"review": {"reportFormat": "..."}}
Model tiers and escalation
The stage table is under Models below.
orchestration.tiers.cheap
The real model behind the cheap tier. Unset, your agent decides.
Change it when: you want a specific model for routine stages.
- Values
- text
- Default
- not set
- Applies to
- all projects, or one
{"orchestration": {"tiers": {"cheap": "..."}}}
orchestration.tiers.standard
The real model behind the standard tier.
- Values
- text
- Default
- not set
- Applies to
- all projects, or one
{"orchestration": {"tiers": {"standard": "..."}}}
orchestration.tiers.strong
The real model behind the strong tier.
- Values
- text
- Default
- not set
- Applies to
- all projects, or one
{"orchestration": {"tiers": {"strong": "..."}}}
orchestration.escalation.enabled
Moves a stalled stage up to a stronger model instead of retrying on the same one.
Change it when: you need a hard ceiling on cost.
- Values
true false- Default
true- Applies to
- all projects, or one
{"orchestration": {"escalation": {"enabled": true}}}
orchestration.escalation.to.model
The tier a stalled stage moves up to.
- Values
- text
- Default
strong- Applies to
- all projects, or one
{"orchestration": {"escalation": {"to": {"model": "strong"}}}}
orchestration.escalation.to.effort
The effort it runs at there.
- Values
low medium high auto- Default
high- Applies to
- all projects, or one
{"orchestration": {"escalation": {"to": {"effort": "high"}}}}
orchestration.escalation.to.isolate
Whether the escalated stage runs in its own subagent.
- Values
true false- Default
false- Applies to
- all projects, or one
{"orchestration": {"escalation": {"to": {"isolate": false}}}}
Models
Each stage runs on a model tier, not a named model: cheap, standard or strong. Your agent maps a tier to a real model. Effort is low, medium, high or auto.
The plan, the failure triage and the review can never go below standard. These are the built-in values:
| Stage | What runs | Tier | Effort | Own subagent |
|---|
orient | Reading the state of the work | cheap | low | no |
plan | Writing the plan | strong | high | no |
code | Writing the code | standard | medium | no |
staticChecks | Lint, typecheck, tests | cheap | low | no |
selfTest | Driving the app | standard | medium | yes |
triage | Working out why something failed | strong | high | no |
review | The code review | strong | high | yes |
manualScenario | Writing your manual test | standard | low | no |
commit | Commit and pull request | cheap | low | no |
postPush | Watching CI | cheap | low | no |
Each stage takes the settings orchestration.stages.<stage>.model, .effort and .isolate. isolate runs the stage in its own subagent, where your agent has them. If it does not, the agent runs that stage itself and says so.
Fields only a project has
These are written when you connect a repo and generate its skills. You rarely edit them by hand.
| Field | What it holds |
path | Where the code lives. |
type | Frontend, backend, CLI and so on. |
commands | The real lint, typecheck, test and launch commands. |
skills | Which generated skills fill the coding, testing, review and repo roles. |