Skip to content

feat: support of AI agents and scripts - #61

Merged
greymag merged 13 commits into
masterfrom
agents-support
Aug 26, 2026
Merged

feat: support of AI agents and scripts#61
greymag merged 13 commits into
masterfrom
agents-support

Conversation

@greymag

@greymag greymag commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Makes alex usable by AI coding agents and scripts, not only by a human in a terminal.

Everything an agent must verify or know becomes a command with a stable exit code and a machine readable report, instead of prose in CLAUDE.md that goes stale on the first new flag. The plan and the reasoning are in docs/agent-support-roadmap.md.

New commands

alex code check — the quality gates in one command: analyze + tests (+ a platform debug build with --build). It replaces the hand written flutter analyze | tail + flutter test | tail pipelines: the output is filtered from a noise, the analyzer issues are parsed into {severity, file, line, column, rule}, the tests run with the JSON reporter so a failure comes with the test name, the suite and a trimmed message — including a suite compilation error. Exit codes: 10 analyze, 11 tests, 12 build. The runner is resolved by the project type (flutter with FVM support, or dart).

alex info — the facts about the project in one call: package and version, root and config path, Flutter or Dart, packages of a multi-package project, the Flutter version pinned with FVM, locales (by the ARB files), l10n paths, git branches.

alex agents guide — a short guide of alex generated from the commands tree of the installed version, so it can't get outdated: the rules an agent needs and every command with its options and exit codes. A command path prints a part of it, --format=json returns a structured index.

alex agents init — writes the alex section into CLAUDE.md / AGENTS.md (or any files from agents.files), so an agent learns about alex from the file it reads first. Only the content between the <!-- alex:begin --> / <!-- alex:end --> markers is touched, broken markers are reported instead of being overwritten, and a symlink between the files is resolved so the section is not written twice. --check fails with exit code 10 for CI.

Common changes

--format=json — supported by code check, info, agents guide, agents init and l10n check_translations. The contract: stdout holds a single JSON object, every other message — including the update banner — goes to stderr. The envelope (alex version, the full command name, ok, exit code, summary) is built in AlexCommand, so no command repeats it. An error object is printed for any failure — an error of a command, a failure of the arguments parsing, a failure before the command is started — so a script always has JSON to parse.

--non-interactive — added automatically to every command that can ask a question (feature finish, pubspec update, custom add). Such a command fails with the name of the option that provides the answer instead of hanging. feature finish also gained --section for the CHANGELOG.md section, and it validates everything it would ask about before any git operation, so it fails before the branch is merged, not after.

Fixed: feature finish looped forever asking for an issue id when there was no input at all (a closed stdin in a script).

Notes

  • No existing behavior changes: --format defaults to text, the human output of every command is the same as before.
  • New config sections: code.check (build target, extra noise patterns) and agents.files.
  • .gitignore: .claude/worktrees/ — nested git worktrees that would otherwise be vendored into a commit.

Checks

dart analyze — no issues. dart test — 165 tests, all pass (63 of them are new: the analyzer and test output parsers, the noise filter, the commands index and the guide renderer, the managed block, the project facts, the raw arguments parsing).

Every commit was reviewed with codex review; the findings are fixed inside the commits they belong to.

greymag and others added 12 commits August 25, 2026 16:37
The `.claude/worktrees/` directory holds nested git worktrees, so an
accidental `git add -A` would vendor a whole second checkout of the
repository. `.claude` itself is left tracked, so shared agent config
can be committed later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Plan of making alex a first-class tool for AI coding agents: the
backlog with priorities and reasons, the JSON output conventions and
the order of work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Runs analyze, tests and (optionally, with `--build`) a debug build of
the platform target, so the whole "is it ready" check is a single
command with a stable contract.

- analyze output is parsed into structured issues, both `flutter
  analyze` and `dart analyze` formats are supported;
- tests are run with the JSON reporter, so a failure is reported with
  the test name, the suite and a trimmed message - including a suite
  compilation error;
- output is filtered from a noise (update banners, dependency
  resolution chatter, third-party deprecations), extra patterns can be
  added with the `code.check.noise` config option;
- runner is resolved by the project type: `flutter` (with FVM support)
  or `dart` for a package without the Flutter dependency;
- exit codes: 10 - analyze failed, 11 - tests failed, 12 - build
  failed.

Also adds the common `--format=json` option: a command prints a single
JSON object with a machine readable report in stdout, while all other
messages - including the update banner - go to stderr.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An agent working in a project has no reason to call a CLI it doesn't
know about, and a hand written description of a CLI goes stale on the
first new flag. So the guide is generated from the commands tree of the
installed version and can't get outdated.

It prints what alex is, the rules an agent needs (config discovery,
the `--format=json` contract, exit codes, which commands are still
interactive) and all commands with their options and exit codes.
A command path argument prints a part of it
(`alex agents guide l10n`), `--format=json` returns a structured index.

To feed the guide, `AlexCommand` gets two optional members: `exitCodes`
with the meaning of the command specific codes and `isInteractive` for
the commands that ask questions in stdin. Both are filled for the
commands that have them today.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`error(1)` is the usual "could not do the job" path in about twenty
places (`pubspec update`, `changelog update-issue-links`, several
`l10n` and `release` commands), but the guide listed only `0`, `2` and
`64`, so an agent would treat a normal failure as an undocumented one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Writes the alex section into the agent instructions of the project
(`CLAUDE.md`, `AGENTS.md` or any file from `agents.files` / `--file`),
so an agent learns about alex from the file it reads first - the
strongest of the channels, because a role agent reads those files
before anything else.

The section is generated from the alex config, `pubspec.yaml` and the
commands tree: package and version, FVM, locales (by the ARB files),
l10n paths, branches, then the commands to use with their exit codes.
So it can be regenerated after any change of the project.

Only the content between the `<!-- alex:begin -->` and
`<!-- alex:end -->` markers is replaced, nothing around it is touched,
and broken markers are reported instead of being overwritten. Files
that point to the same file through a link (the usual
`AGENTS.md -> CLAUDE.md`) are deduplicated, so the section is not
written twice. With `--check` nothing is changed and the command fails
with exit code 10 if some file is missing or outdated - for CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- a locale can have a numeric region (`es_419`, `en_001`) or be written
  through a dash, so it is not only letters and underscores;
- `intl_messages.arb` matches the ARB pattern too, but it's the file
  with the extracted messages, not a locale - the name is taken from
  `L10nUtils.arbMessagesSuffix`, so it can't diverge from the l10n
  commands;
- an extra closing marker of the managed block is reported as a broken
  file too, not only a second opening one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Package and version, root and config path, Flutter or Dart, packages
of a multi-package project, the Flutter version pinned with FVM,
locales (by the ARB files) and localization paths, git branches - in
one call with `--format=json`, instead of reading several files.

The facts are collected by the same `ProjectFacts` as `agents init`
uses for the section it writes, so the two can't disagree. The
localization facts are skipped when the project has no ARB directory,
so a project that doesn't use the alex l10n gets no facts about
directories that don't exist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four commands built the `--format=json` envelope by hand, each with its
own hardcoded command name. Now `jsonResult()` in `AlexCommand` builds
it: the alex version, the full name taken from the commands tree
(`code check`, `agents init`), `ok`, the exit code and a summary.

It also makes the contract hold on every path out of a command. Before,
a command that failed by returning `error(...)` - not by throwing -
printed nothing in stdout, and a failure before the command was started
(arguments parsing, initialization) went to `app.dart` and bypassed the
result completely. Both print an error object now, so a script always
has JSON to parse; the raw arguments are checked for the option in
`json_format.dart`, because at that point they may be unparseable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`--format=json` prints the result of every check as a JSON object: a
stable `id` (`arb_untranslated`, `xml_duplicates`, `code_not_generated`
and so on), what the check expects, the status, and for a failed one -
the problems with the locale and the keys. So CI or an AI agent reacts
to a particular problem instead of parsing the detailed human report,
which stays in stderr as before.

The files changed after `pub get` are reported in `changedFiles` in
both cases: when `--fail-on-changed-files` makes it an error and when
it's only a warning - a script should be able to see that the
dependencies are not in sync either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A command that waits for an answer in stdin can't be used by a script
or an AI agent: it just hangs. `--non-interactive` makes such a command
fail with the name of the option that provides the answer instead.

The flag is added to the parser automatically for a command whose
`isInteractive` is `true`, so a new interactive command can't forget it,
and `alex agents guide` prints it for every `[INTERACTIVE]` command.

`feature finish` needed the most:

- new `--section` option (`added`, `fixed` or `pre-release`) instead of
  choosing the CHANGELOG.md section interactively, `added` by default -
  as it is for an empty answer;
- `--issue` and `--changelog` are checked BEFORE any git operation, so
  the command fails before the branch is merged, not after it;
- an empty `--changelog=` skips the changelog, as the message about the
  missing option says - it doesn't fall back to the question;
- fixed a real hang: the issue id prompt looped forever when there was
  no input at all (a closed stdin in a script), because `readLineSync`
  keeps returning null.

`pubspec update` fails naming `--dependency`. `custom add` is a wizard
by nature, so it points to the config file to edit directly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes alex usable by AI coding agents and scripts, not just interactive terminal users. It adds a machine-readable --format=json mode, a --non-interactive flag for every command that reads stdin, and new commands that expose project facts and a self-generated tool guide. Existing text/human output is unchanged (--format defaults to text).

Changes:

  • New commands: code check (analyze/test/build quality gates with parsed, de-noised output), info, and the agents group (guide, init) that generate documentation from the command tree.
  • Cross-cutting --format=json envelope built centrally in AlexCommand (with stdout reserved for JSON, all messages routed to stderr), plus --non-interactive auto-added to interactive commands (feature finish, pubspec update, custom add), and a fix for the feature finish infinite issue-id prompt on closed stdin.
  • New config sections (code.check, agents.files), supporting parsers/models under lib/src/check and lib/src/agents, docs, and 63 new tests.

Reviewed changes

Copilot reviewed 40 out of 41 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lib/runner/alex_command.dart Adds fullName, isInteractive/exitCodes, JSON envelope, non-interactive helpers, error capture
lib/runner/alex_command_runner.dart Registers new commands; routes messages to stderr in JSON mode
lib/internal/print.dart Adds message sink switch and result() for stdout JSON
lib/app.dart Emits JSON error object for pre-command failures
lib/src/output/json_format.dart Raw-args detection of JSON format and command name
lib/src/const.dart New option/flag name constants
lib/src/config.dart Adds agents and code.check config models
lib/commands/code/check_command.dart New quality-gates command
lib/commands/code/code_command.dart Wires up check subcommand
lib/commands/agents/*.dart New agents guide/init commands
lib/commands/info_command.dart New info command
lib/commands/feature/finish_command.dart Adds --section, non-interactive validation, stdin fix
lib/commands/pubspec/update_command.dart, custom/add_custom_command.dart Non-interactive handling
lib/commands/l10n/check_translation_command.dart JSON report with stable check ids
lib/src/check/*.dart Analyze/test output parsers, filters, report models
lib/src/agents/*.dart Command index, guide/section renderers, project facts, managed block
test/** New unit tests for parsers, renderers, index, facts, managed block
README.md, CHANGELOG.md, docs/agent-support-roadmap.md, alex.yaml, .gitignore Documentation and config updates

Findings are limited: a multi-option empty-list default is rendered as a literal [] in the generated guide/index (command_index.dart), and a minor grammar nit ("filtered from a noise"). No functional defects were found, and the new parsing/rendering logic is well covered by tests.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/commands/code/check_command.dart Outdated
Comment thread lib/src/agents/command_index.dart Outdated
`addMultiOption` without `defaultsTo` gives an empty `List`, not `null`,
so the guide printed `(default: [])` for the `--file` option of
`agents init`. In a machine readable index such a value is worse than
no value: it looks like a real default. An empty collection is treated
as "no default" now, the same as `false` for a flag.

Also fixes the wording of the `code check` description, which is shown
in the help and in the generated guide: "filtered from noise".

Both are from the Copilot review of #61.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@greymag

greymag commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

@copilot both findings are fixed in 13e4a97, please take another look.

1. Empty-list default in the commands index — confirmed and fixed. addMultiOption without defaultsTo gives an empty List rather than null, so alex agents guide agents init really did print:

- `--file=<value>` - File with the agent instructions to add the section in. Can be passed multiple times. (default: [])

An empty collection is treated as "no default" now, the same way false already was for a flag. In a machine readable index a bogus default is worse than no default — an agent can take [] for a real value. Covered by a test: a multi option without defaultsTo reports no default, one with defaultsTo: ['en'] still reports [en].

2. "filtered from a noise" — fixed everywhere the phrasing occurred, not only in the command description: README.md, CHANGELOG.md, alex.yaml and the doc comments in output_filter.dart / config.dart. The description is user-facing twice over — in --help and in the generated alex agents guide — so it was worth doing properly.

Gates after the fix: dart analyze — no issues, dart test — 166 passed.

Copilot AI commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

@copilot both findings are fixed in 13e4a97, please take another look.

1. Empty-list default in the commands index — confirmed and fixed. addMultiOption without defaultsTo gives an empty `L...

Confirmed in 13e4a97 — the empty-list default is no longer reported, the wording is corrected, and the targeted test plus analyze pass locally. No further changes are needed from me.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.

@greymag
greymag merged commit def993c into master Aug 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants