Skip to content

Conformance Task Architecture

xtarterize applies conformance configuration through discrete, independently applicable tasks. Each task inspects one area of a project, reports a status, previews its changes, and applies them without assuming other tasks have run.

Every task declares:

  • id, label, and group for selection and reporting
  • scope: where the task runs in a monorepo (root, package, or both; the default is both)
  • applicable(profile): whether the task matches the detected project
  • check: the current status, one of new, patch, skip, or conflict
  • dryRun: the file diffs the task would write
  • apply: the write itself
  • An optional dependency declaration, which the apply plan collects and installs in one batch before any task runs

Task methods return Effects. A spec may be synchronous, return a Promise, or return an Effect; the task factory normalizes all three before the engine calls them. The only service required today runs external processes.

Most tasks come from a declarative spec rather than a hand-written implementation. A spec declares metadata, applicability, targets, actions, and dependencies. It resolves once per call, and status, diffs, apply, and dependency collection all project from that resolution, so a task’s status cannot disagree with its diffs.

A target is one file the task claims, plus how its content is computed:

  • text: rendered content; an absent file is new, equal content is skip, differing content is conflict
  • jsonMerge: an incoming object merged into existing JSON; an absent file is new, a real change is patch, no change is skip
  • packageJson: a change applied through the package.json owner; the same statuses as a JSON merge, plus new when the file is absent
  • transform: content in and content out on a discovered file, such as a Vite config; a real change is patch

A target can override its projected status when the content warrants it, for example to report conflict instead of overwriting a user value.

An action reports a status and runs a side effect without producing a file diff, such as installing agent skills. Use an action when the work is not a config file.

Dependencies are part of the resolution. A task can declare a fixed list or compute one from the resolved status and diffs, so it only requests a package when the run needs it. The apply plan installs everything in one batch before any task runs.

One shared module is the only xtarterize writer of package.json. It patches the current file text, so comments, indentation, and key order survive, and it recomputes the change at apply time, so entries added by the package manager or another task are kept.

JSON merge targets project a tristate status to avoid permanent patch loops. A missing key is added (patch), a matching value is skip, and a differing value is left in place unless the target policy forces conflict.

  1. Declare the task with the task factory: id, label, group, applicability, targets or actions, and dependencies. Start from a nearby task in the repository.
  2. Register it in the task registry.
  3. Verify idempotency: a second run reports no changes.
  4. Add or update tests when they protect a real regression, and extend the nearest existing suite when possible.
Learn about the overall architecture