Skip to content

agent update: tell an agent what an upgrade changed and what to do about existing rules #180

Description

@thecodedrift

Summary

Add an agent update instruction set: a recipe that tells an agent what changed in a Taskless upgrade and what to do about the rules already in the project.

Today an engine upgrade is silent from the rule author's side. The vendored ast-grep or Vale version moves, the schema regenerates, and an existing rule either keeps working, starts failing verify, or quietly matches a different set of nodes. Nothing tells the agent which of the three happened, or what the new layout expects.

Why now

The 0.41.0 to 0.45.2 ast-grep upgrade (#162) is the first one with a real migration surface, and it is a good small case to build against:

  • A tightened requirement. fix is now required on a rewriter (SerializableRewriter.required moves from ["rule","id"] to ["id","fix","rule"]). A rewriter without one was accepted before and is rejected now. It could never have worked, so this surfaces a latent bug rather than breaking behavior, but the author still has to act.
  • New capabilities. Markdown and Dart become available languages, and Markdown in particular comes with sharp limits (block grammar only, no inline nodes, no counts or absence) that an author will get wrong without guidance.
  • Changed matching semantics. Metavariable binding no longer leaks across nthChild siblings or out of a negated not, and root metavariables now match comments. A valid, unchanged rule can match a different set of nodes with no error.

The third class is the one an author cannot discover on their own.

What the recipe should do

taskless agent update (name to be decided) should answer, for the version being moved to:

  1. What changed in the engines, in rule-author terms rather than changelog terms.
  2. What in this project is affected. Concretely: scan .taskless/rules/ and name the rules touched by each change, rather than describing the change abstractly and leaving the author to grep.
  3. What to do about each, split by whether it is mechanical or authorial. A rewriter missing fix cannot be auto-fixed, because fix is replacement text and therefore intent; the recipe should surface the rule and help the author write it, not silently transform it.
  4. What is newly possible. New languages and new constructs, with the caveats attached, so an upgrade is also an opportunity rather than only a chore.
  5. What cannot be checked. Where matching semantics changed, say so plainly and name the affected constructs, so an author knows to re-run test against fixtures rather than assuming silence means safety.

Notes

  • Pre-1.0, some sloppiness across upgrades is acceptable. The goal is not a guaranteed-safe migration, it is that the author is told what happened and is not left to discover it from a rule that stopped firing.
  • This is the agent-facing counterpart to the changeset. The changeset says what changed in the release; this says what it means for the rules in front of you.
  • Related: The .taskless/ migration is invisible to the machine interface #178 tracks the .taskless/ migration being invisible to the machine interface. Same theme, different surface: this issue is about the rules, The .taskless/ migration is invisible to the machine interface #178 is about the directory layout.

Refs #162
Refs #178
Refs TSKL-291

Registration in the root skill

The recipe is not discoverable unless the root skill routes to it. skills/taskless/SKILL.md carries a Topics table mapping an intent to npx @taskless/cli agent <topic>, and this needs a row alongside the existing ones (route, onboard, improve-rule, delete-rule, check, auth, ci).

The row should say what the recipe is for, in the terms an agent will be thinking in: determining whether rule rewriting is necessary beyond what the standard Taskless migration already does.

That distinction is the point of the skill, and it needs stating plainly in both the root skill and the recipe itself:

  • The standard migration rewrites the layout. Running check or verify migrates the .taskless/ directory structure in place. It is automatic and an agent does not have to reason about it. Its invisibility to the machine interface is The .taskless/ migration is invisible to the machine interface #178.
  • This recipe covers what migration cannot touch: the content of the rules. A rewriter that now requires fix, a rule whose matching semantics shifted under a new engine version, a rule that could now be expressed better with a newly supported language. None of that is a layout change, none of it is mechanical, and the standard migration will never do it.

An agent that has run a migration and seen it succeed will otherwise reasonably conclude the upgrade is complete. The root skill entry exists to say: the directory is migrated, the rules may still need work, and here is how to find out.

Naming: agent update is already taken

packages/cli/src/agent/update.txt exists and means something else: refreshing the installed Taskless skills in the user's coding-agent tools to the bundled version, via taskless update. That is a tooling refresh with no view of rules at all.

Two jobs now collide on the word "update":

topic meaning
existing agent update refresh installed skills to the bundled version
this recipe decide whether rules need rewriting after an engine or CLI upgrade

Pick a distinct topic name (agent migrate-rules, agent upgrade-rules, or similar) rather than overloading update, and cross-reference the two so an agent that lands on the wrong one is redirected. Whatever it is called, the root skill table needs to make the difference obvious at a glance, since an agent choosing from that table has only one line to go on.

Decided: reclaim the update name

The existing agent update topic is going away. Refreshing installed skills is the CLI's job (taskless update), not a recipe's, so a skill topic explaining it earns nothing. packages/cli/src/agent/update.txt should be removed or reduced, and update becomes this recipe. The naming collision noted above resolves itself; no migrate-rules alias is needed.

Structure: a sequential ledger, one section per version

The recipe is a list of sections, in release order:

## Migrating to 0.11.0
<what an agent must do about existing rules>

## Migrating to 0.12.0
No agent work for this version.

An agent starts at the project's last reconciled version and walks forward to the installed one, doing what each section says.

Two properties matter:

  • Every released version gets a section, including the empty ones. A version with nothing to do says so explicitly. Silence is ambiguous: an agent cannot tell "nothing to do here" from "nobody wrote this section", and the whole point of the recipe is to remove that ambiguity. An explicit no-op is a claim; a missing section is an unknown.
  • Sections are cumulative, not replaceable. An agent three versions behind must get all three, in order, because a later migration can depend on an earlier one having run.

Correction: install.cliVersion is maintained, and this section previously said it was not

An earlier version of this section claimed, as a measurement, that this repository's taskless.json reads 0.6.0 while running 0.11.0, and concluded that nothing advances the field. That reading was taken from a git worktree checked out at origin/main, not from the working branch, and the conclusion drawn from it was wrong.

Measured properly:

ref version install.cliVersion
origin/main 2 0.6.0
the onboarding branch (210ac00) 5 0.11.0-20260824213902xf26a7b0

The directory-structure handling does what it should: it migrated the config version and wrote the current CLI version. main lags only because the onboarding commits are on a branch that has not landed there.

The real question about a start marker

install.cliVersion is maintained, so it is a candidate. What it is not is a statement about rules.

It records the version that last migrated the layout. A layout migration bumps it without any agent having read a single rule, so a project can carry a current cliVersion and still have rules that nobody reconciled against the engine changes in that release. Keying the ledger off it would mean an agent skips migrations it never performed, which fails in the quiet direction: the walk reports nothing to do and the rules stay wrong.

So the decision is whether the ledger:

  1. Reuses install.cliVersion, accepting that a layout migration silently marks rule work as done. Cheapest, and wrong whenever the two diverge.
  2. Adds a separate marker meaning "rule content reconciled up to X", advanced only when the agent completes a walk. Correct, and it raises the questions below.

If a separate marker:

  • Where it lives. taskless.json is the obvious home, though it currently describes installation rather than rule state.
  • Who advances it. A partial or abandoned walk must not record completion, so the agent claiming success is not sufficient on its own.
  • A fresh project with no marker. Probably record the current version and do nothing, since a project created at 0.11.0 has no history to migrate, but it should be stated rather than inferred.
  • A marker ahead of the installed CLI, which is the downgrade case.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions