feat: support of AI agents and scripts - #61
Conversation
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>
There was a problem hiding this comment.
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 theagentsgroup (guide,init) that generate documentation from the command tree. - Cross-cutting
--format=jsonenvelope built centrally inAlexCommand(with stdout reserved for JSON, all messages routed to stderr), plus--non-interactiveauto-added to interactive commands (feature finish,pubspec update,custom add), and a fix for thefeature finishinfinite issue-id prompt on closed stdin. - New config sections (
code.check,agents.files), supporting parsers/models underlib/src/checkandlib/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.
`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>
|
@copilot both findings are fixed in 13e4a97, please take another look. 1. Empty-list default in the commands index — confirmed and fixed. An empty collection is treated as "no default" now, the same way 2. "filtered from a noise" — fixed everywhere the phrasing occurred, not only in the command description: Gates after the fix: |
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. |
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.mdthat goes stale on the first new flag. The plan and the reasoning are indocs/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 writtenflutter analyze | tail+flutter test | tailpipelines: 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:10analyze,11tests,12build. The runner is resolved by the project type (flutterwith FVM support, ordart).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=jsonreturns a structured index.alex agents init— writes the alex section intoCLAUDE.md/AGENTS.md(or any files fromagents.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.--checkfails with exit code10for CI.Common changes
--format=json— supported bycode check,info,agents guide,agents initandl10n 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 inAlexCommand, 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 finishalso gained--sectionfor 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 finishlooped forever asking for an issue id when there was no input at all (a closed stdin in a script).Notes
--formatdefaults totext, the human output of every command is the same as before.code.check(build target, extra noise patterns) andagents.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.