dart-args-production-cli
Skill8 starsChanged 48 days agoMITView on GitHub
Design, implement, review, debug, test, and evolve Dart and Flutter command-line interfaces with package:args. Use whenever work mentions ArgParser, ArgResults, Command, CommandRunner, flags, options, subcommands, package executables, Dart CLI tooling, Flutter companion scripts, CI/release utilities, or Flutter desktop entrypoint arguments. Also use this skill to decide whether package:args belongs at all; reject it for ordinary Flutter mobile/web settings, routes, deep links, URL query parameters, or build-time configuration unless the executable genuinely receives process command-line arguments.
In this repository70 other files it gives its agents.
- camerawesome-flutterSkill
- dart-flutter-equatable-engineeringSkill
- dart-flutter-ffi-systems-engineeringSkill
- dart-metaSkill
- document-camera-frameSkill
- document-scan-flutterSkill
- figma-to-flutter-expertSkill
- flutter-animations-production-engineeringSkill
- flutter-app-hardening-reverse-engineeringSkill
- flutter-app-icon-engineeringSkill
- flutter-application-security-engineeringSkill
- flutter-app-links-deep-link-engineeringSkill
- flutter-cachingSkill
- flutter-concurrency-memory-performanceSkill
- flutter-confetti-engineeringSkill
- flutter-dart-package-engineeringSkill
- flutter-design-system-from-design-mdSkill
- flutter-dio-cache-interceptor-engineeringSkill
- flutter-dio-engineeringSkill
- flutter-doc-scannerSkill
- flutter-drift-persistence-engineeringSkill
- flutter-expert-tipsSkill
- flutter-firebase-analyticsSkill
- flutter-firebase-core-engineeringSkill
- flutter-firebase-messagingSkill
- flutter-get-it-injectable-dependency-injectionSkill
- flutter-go-router-engineeringSkill
- flutter-hive-persistence-engineeringSkill
- flutter-image-performanceSkill
- flutter-image-picker-production-engineeringSkill
- flutter-lints-static-analysis-engineeringSkill
- flutter-local-notifications-production-engineeringSkill
- flutter-memory-leak-engineeringSkill
- flutter-mobile-developmentSkill
- flutter-motion-engineeringSkill
- flutter-multi-environmentSkill
- flutter-native-splash-engineeringSkill
- flutter-package-plugin-selectionSkill
- flutter-path-provider-production-storageSkill
- flutter-performance-jank-optimizationSkill
- flutter-permission-handler-engineeringSkill
- flutter-pinputSkill
- flutter-production-build-releaseSkill
- flutter-production-engineeringSkill
- flutter-production-loggingSkill
- flutter-pro-image-editor-engineeringSkill
- flutter-secure-storage-security-engineeringSkill
- flutter-sentry-engineeringSkill
- flutter-share-plus-engineeringSkill
- flutter-skeletonizer-engineeringSkill
- flutter-squadron-concurrency-engineeringSkill
- flutter-supabase-engineeringSkill
- flutter-svg-engineeringSkill
- flutter-ui-performance-engineeringSkill
- flutter-url-launcher-engineeringSkill
- flutter-video-player-production-engineeringSkill
- flutter-webview-production-engineeringSkill
- freezed-production-engineeringSkill
- html-to-flutterSkill
- hydrated-blocSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
36 rules. About 0 are common, 17 are distinctive, and 19 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈17
Distinctive · estimate
This author's own choices. Worth a look.
19
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 11
Use this skill as the decision and implementation layer for production Dart/Flutter CLI work.
- Very specific: line 13
Treat package:args as an adapter for process or Dart-entrypoint arguments.
- Distinctive: line 17
Use this skill for:
- Very specific: line 28
Do not activate args merely because:
- Very specific: line 40
If the project resolves another version, inspect pubspec.lock, the current official API, and the changelog before relying on …
- Very specific: line 137
Do not use CommandRunner merely to make a tiny script look architectural.
- Distinctive: line 177
Use canonical option names.
- Very specific: line 266
Do not overload ArgParser with application semantics.
- Very specific: line 284
Use 0 for success by convention.
- Distinctive: line 285
Use documented non-zero codes for expected failures when automation depends on them.
- Very specific: line 286
Prefer setting top-level dart:io exitCode after awaited cleanup.
- Very specific: line 287
Avoid deep exit() calls; exit() is immediate and does not wait for async operations or run finally blocks.
- Very specific: line 294
read argResults at the boundary.
- Distinctive: line 297
call an application service.
- Distinctive: line 300
Keep business logic out of the command class.
- Very specific: line 334
Use valueHelp for values such as path, mode, uri, or seconds.
- Very specific: line 335
Use allowedHelp when enum-like values need explanation.
- Very specific: line 336
Use ArgParser.usage for plain parsers.
- Distinctive: line 342
Use CLI arguments for explicit per-invocation user/script input.
- Distinctive: line 344
Use other mechanisms when they own the data:
- Very specific: line 352
When sources combine, define precedence explicitly and use wasParsed() when you must distinguish an explicit CLI value from a parser …
- Distinctive: line 358
Do not model deep links, platform intents, or normal app settings as command-line arguments.
- Very specific: line 362
Do not use package:args to parse browser paths, fragments, or query parameters.
- Very specific: line 370
Prefer a separate Dart CLI for Flutter build/release/migration/generation tasks rather than coupling the Flutter UI runtime to CLI types.
- Very specific: line 390
Prefer secret stores, protected environment injection, stdin, restricted files, or OS credential stores where appropriate.
- Distinctive: line 394
Do not invent benchmark claims.
- Very specific: line 408
Prefer direct parser/runner tests with List<String>.
- Distinctive: line 422
Use subprocess tests only for actual process contracts such as exit codes, stdout/stderr, executable packaging, or launcher behavior.
- Distinctive: line 426
Treat option names, aliases, commands, defaults, output schema, and exit status as public contracts when automation depends on them.
- Distinctive: line 432
Never approve these without a specific justified exception:
- Distinctive: line 438
every validation rule forced into parser declaration.
- Very specific: line 439
every exception converted to UsageException.
- Distinctive: line 451
Read only the reference relevant to the task:
- Distinctive: line 474
Use current typed APIs.
- Very specific: line 477
Keep domain/application logic independent of package:args.
- Distinctive: line 478
Keep output and services testable.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Dart package:args — Production CLI Engineering Skill
Purpose
Use this skill as the decision and implementation layer for production Dart/Flutter CLI work.
Treat package:args as an adapter for process or Dart-entrypoint arguments. Do not treat it as a general Flutter settings, navigation, persistence, environment, or configuration library.
Trigger Rules
Use this skill for:
- Dart command-line applications and package executables.
ArgParser,ArgResults, flags, options, multi-options, aliases, positionals, and parsing errors.Command<T>,CommandRunner<T>, commands, subcommands, help, and usage failures.- Flutter companion tooling such as release, build, localization, migration, asset, bootstrap, and code-quality utilities.
- CI/CD utilities implemented in Dart.
- Flutter Windows/macOS/Linux apps that intentionally receive Dart entrypoint arguments.
- Reviewing, debugging, testing, migrating, or optimizing existing
package:argscode. - Deciding whether
package:argsis appropriate at all.
Do not activate args merely because:
- a Flutter app has settings;
- a web app has query parameters;
- an app receives a deep link;
- the project uses
--dart-define; - configuration must persist between launches.
Research Baseline
This skill targets current stable package:args 2.7.0, minimum Dart 3.3. Current relevant features include typed ArgResults.flag(), option(), and multiOption(), aliases, mandatory single options, hideNegatedUsage, and generic Command<T> / CommandRunner<T>.
If the project resolves another version, inspect pubspec.lock, the current official API, and the changelog before relying on version-sensitive behavior. Never copy an unreleased API from the repository default branch into code targeting 2.7.0.
Core Principles
- MUST determine whether the executable genuinely receives process/Dart-entrypoint arguments before adding
package:args. - MUST parse at the outer boundary: normally
main(List<String> arguments), a CLI adapter, orCommand.run(). - MUST convert
ArgResultsinto typed application data promptly. Domain/application services should not depend onpackage:args. - MUST separate parser/syntax validation from semantic/domain validation.
- MUST parse one invocation once.
- SHOULD centralize parser construction and canonical option names.
- SHOULD use typed
ArgResultsaccessors rather than dynamicoperator []in new code. - SHOULD treat CLI syntax and defaults as public API once scripts or users depend on them.
- SHOULD scope options to the narrowest meaningful command.
- SHOULD keep parser construction declarative and side-effect-free.
- SHOULD create heavy dependencies after parsing/command selection when startup cost justifies it.
- SHOULD NOT use parser callbacks as the main application-control mechanism. Parse first, map, validate, then execute.
- SHOULD NOT put secrets in command arguments by default.
- NEVER use
package:argsfor browser URL/query parsing or mobile deep-link parsing. - NEVER confuse
Platform.executableArgumentswith the program argument list. Program args normally come frommain(List<String>). - PREFER correctness, discoverability, stable behavior, and testability over parser micro-optimization.
First Decision: Should package:args Be Used?
Does the executable receive process/Dart-entrypoint arguments?
|
+-- No
| `-- Do not use package:args.
|
`-- Yes
|
+-- Is this ordinary Android/iOS/Web app configuration?
| `-- Usually do not use package:args.
| Use routes/deep links, runtime state/config,
| environment declarations, platform APIs, or persistence.
|
+-- Tiny single-purpose executable?
| `-- Use ArgParser directly.
|
+-- Meaningful commands/subcommands?
| `-- Prefer CommandRunner + Command.
|
`-- Flutter desktop app deliberately launched with arguments?
`-- Parse only arguments intentionally forwarded to Dart main().Flutter Platform Matrix
| Target/use case | Typical relevance | Preferred pattern |
| Flutter Android runtime | Low | Deep links/intents/runtime config/persistence/build-time declarations |
| Flutter iOS runtime | Low | Deep links/universal links/runtime config/persistence/build-time declarations |
| Flutter Web runtime | Very low for process args | Router, Uri, browser URL/query handling, compilation environment |
| Flutter Windows desktop | Medium when deliberately wired | Dart entrypoint args at main(List<String>) |
| Flutter macOS desktop | Medium/high when launch args matter | Dart entrypoint args at main(List<String>) |
| Flutter Linux desktop | Medium/high when launch args matter | Dart entrypoint args at main(List<String>) |
| Flutter project companion CLI | High | Separate bin/ or tool/ Dart CLI |
| CI/CD Dart utility | High | Stable deterministic CLI |
Desktop capability does not imply every GUI app should expose CLI syntax. Verify the native/generated runner when exact Windows/macOS/Linux forwarding behavior matters.
Mental Model
shell / launcher / native embedder
↓
List<String>
↓
ArgParser / CommandRunner
↓
ArgResults
↓
validate + map at boundary
↓
typed immutable config/request
↓
application/domain logicArgResults is an adapter-layer object, not application state.
Choose the Right Abstraction
Use plain ArgParser when
- the executable has one main operation;
- it has a modest set of flags/options/positionals;
- manual dispatch remains trivial.
Use CommandRunner when
- there are several meaningful commands;
- commands have distinct option sets;
- subcommands improve the user model;
- built-in help/dispatch/usage behavior is valuable;
- commands should be independently testable.
Do not use CommandRunner merely to make a tiny script look architectural.
Core API Rules
ArgParser
Use current APIs:
final parser = ArgParser()
..addFlag(
'verbose',
abbr: 'v',
negatable: false,
help: 'Show additional diagnostics.',
)
..addOption(
'mode',
defaultsTo: 'debug',
allowed: const ['debug', 'release'],
valueHelp: 'mode',
)
..addMultiOption(
'include',
splitCommas: false,
valueHelp: 'path',
);ArgResults
Prefer:
final verbose = results.flag('verbose');
final mode = results.option('mode');
final includes = results.multiOption('include');
final positional = results.rest;Use canonical option names. Aliases are invocation syntax, not separate application keys.
Mandatory option nuance
A missing mandatory: true single option is validated when the value is retrieved from ArgResults, not simply when parse() is called. Read/convert required values immediately at the CLI boundary and handle the resulting ArgumentError as expected user input where appropriate.
Multi-options
Repeated values accumulate. By default comma-separated values split as well. Set splitCommas: false when commas are literal or when one repeated-option grammar is preferred.
Flags
Flags are negatable by default. Use negatable: false when --no-... is not a sensible public contract. Avoid double-negative names.
--
-- ends option parsing. Use it before dash-prefixed positional values such as filenames or negative numbers when ambiguity is possible.
Trailing options
ArgParser() defaults to allowTrailingOptions: true. Set it to false only when the CLI intentionally stops parsing options after the first positional.
Required Typed Boundary
Convert parser output before entering application logic:
enum BuildMode { debug, release }
final class BuildRequest {
const BuildRequest({
required this.mode,
required this.outputDirectory,
required this.verbose,
});
final BuildMode mode;
final String outputDirectory;
final bool verbose;
}
BuildRequest parseBuildRequest(ArgResults results) {
final mode = switch (results.option('mode')) {
'debug' => BuildMode.debug,
'release' => BuildMode.release,
final value => throw ArgumentError.value(value, 'mode'),
};
final output = results.option('output');
if (output == null || output.trim().isEmpty) {
throw ArgumentError('Provide a non-empty --output value.');
}
return BuildRequest(
mode: mode,
outputDirectory: output,
verbose: results.flag('verbose'),
);
}For a larger codebase, keep this mapper in the CLI adapter layer so domain-owned request objects do not import package:args.
Validation Model
Parser/syntax validation
Let args handle:
- known option/flag names;
- required option values;
allowedmembership;- negation syntax;
- command recognition;
- parser definition conflicts.
Semantic/domain validation
Handle after parsing:
- required positional count;
- mutually exclusive options;
- cross-field rules;
- numeric ranges;
- URIs;
- paths/filesystem state;
- permissions;
- business constraints.
Do not overload ArgParser with application semantics.
Error Policy
Plain parser
- Malformed CLI grammar: catch
ArgParserException(FormatException). - Missing mandatory single option on retrieval: handle
ArgumentErrorwhere it represents user input. - Unexpected programmer/runtime failures: do not disguise them as parser failures.
CommandRunner
Catch UsageException for user-correctable invocation errors. Let unexpected defects follow the program’s normal diagnostic policy.
Exit status
package:args does not define your exit-code taxonomy.
- Use
0for success by convention. - Use documented non-zero codes for expected failures when automation depends on them.
- Prefer setting top-level
dart:ioexitCodeafter awaited cleanup. - Avoid deep
exit()calls;exit()is immediate and does not wait for async operations or runfinallyblocks.
Command Architecture
A production Command<T> should:
- declare command-local syntax;
- read
argResultsat the boundary; - validate semantics;
- build a typed request;
- call an application service;
- return a small status/result if the runner uses one.
Keep business logic out of the command class.
final class BuildCommand extends Command<int> {
BuildCommand(this._service) {
argParser
..addOption(
'mode',
defaultsTo: 'debug',
allowed: const ['debug', 'release'],
)
..addFlag('verbose', negatable: false);
}
final BuildService _service;
@override
String get name => 'build';
@override
String get description => 'Build project artifacts.';
@override
Future<int> run() async {
final request = parseRequest(argResults);
await _service.build(request);
return 0;
}
}Help and Version
- Give every public option/command useful
helptext. - Use
valueHelpfor values such aspath,mode,uri, orseconds. - Use
allowedHelpwhen enum-like values need explanation. - Use
ArgParser.usagefor plain parsers. - Let
CommandRunnerprovide its built-in help command and--helphandling. - Implement
--versionexplicitly; do not assumeCommandRunnerdoes it automatically.
Configuration Source Rules
Use CLI arguments for explicit per-invocation user/script input.
Use other mechanisms when they own the data:
- environment variables for process/deployment-owned configuration;
- config files for structured reusable settings;
- Flutter
--dart-define/ constant environment declarations for compile-time/build configuration; - routes/deep links/
Urifor navigation and browser/mobile URLs; - persistence/state for application settings.
When sources combine, define precedence explicitly and use wasParsed() when you must distinguish an explicit CLI value from a parser default.
Flutter Rules
Android/iOS
Do not model deep links, platform intents, or normal app settings as command-line arguments. Prefer Flutter navigation/deep-link APIs and platform/runtime configuration.
Web
Do not use package:args to parse browser paths, fragments, or query parameters. Use Uri, Uri.base, router APIs, and browser mechanisms.
Desktop
main(List<String> arguments) can be an intentional launch boundary when the Windows/macOS/Linux embedder or launcher forwards entrypoint arguments. Verify the target runner if behavior is contract-critical.
Companion tooling
Prefer a separate Dart CLI for Flutter build/release/migration/generation tasks rather than coupling the Flutter UI runtime to CLI types.
Package Executables
- Public tools:
bin/. - Private development-only tools: top-level
tool/. - Expose public commands through
pubspec.yamlexecutableswhen needed. - During development, use
dart run ...and pass program arguments after the target. - On Dart 3.10+, prefer
dart installfor global CLI installation. dart pub global activateremains relevant for legacy/older SDK compatibility but is now legacy guidance.
Security Rules
Review whether argument values can appear in:
- shell history;
- process inspection;
- CI command logs;
- verbose/error output.
Prefer secret stores, protected environment injection, stdin, restricted files, or OS credential stores where appropriate. package:args does not encrypt or redact values.
Performance Rules
Do not invent benchmark claims.
Optimize only after measurement. Prioritize:
- expensive I/O before parsing;
- unnecessary Flutter engine/UI startup for pure tooling;
- eager network/database initialization;
- constructing every command’s heavy services before selection;
- repeated parsing.
A normal parser and one parse() call are rarely the first place to speculate about performance.
Testing Rules
Prefer direct parser/runner tests with List<String>.
Unit-test:
- defaults and explicit values;
- flag negation;
- allowed-value failures;
- multi-options;
- positionals and
--; - aliases and
wasParsed()where relevant; - command selection;
- semantic validation;
- usage failures.
Use subprocess tests only for actual process contracts such as exit codes, stdout/stderr, executable packaging, or launcher behavior.
Compatibility Rules
Treat option names, aliases, commands, defaults, output schema, and exit status as public contracts when automation depends on them.
For renames, prefer a migration period using aliases. Changing a default can be breaking even when syntax still parses.
Common Anti-Patterns
Never approve these without a specific justified exception:
ArgParserinside ordinary Flutter widget/business code.ArgResultspassed into services/repositories/domain objects.- scattered
results['key']access. - business logic in parser callbacks.
- every validation rule forced into parser declaration.
- every exception converted to
UsageException. - CLI args used as secret storage.
- duplicated/shadowed global and command-local option names.
- unstable aliases/abbreviations/defaults.
- repeated parsing of the same invocation.
- expensive I/O during parser construction.
- deep
exit()inside async work. - Android/iOS/Web treated as generic desktop CLI processes.
- parser optimization without profiling.
Reference Loading Guide
Read only the reference relevant to the task:
references/parser-api.md—ArgParser,ArgResults, options, flags, multi-options, aliases, abbreviations, positionals, ordering,--, and current API inventory.references/commands-and-validation.md—CommandRunner,Command, nested commands, typed configuration, custom types, paths, and two-stage validation.references/flutter-and-operations.md— errors, exits, help/version, config precedence, Flutter integration, desktop arguments, package executables, output, security, performance, async cleanup, CI, and evolution.references/testing-and-review.md— full tests, production templates, decision trees, edge cases, anti-patterns, debugging, and review checklists.references/sources.md— authoritative source URLs plus final validation checklist; read this whenever an API/version/platform behavior is uncertain.
AI Operating Procedure
Before implementation
- Identify the executable and platforms.
- Confirm the input is actual process/Dart-entrypoint argv.
- Decide whether another configuration mechanism owns the input better.
- Inspect the resolved
argsversion if version-sensitive. - Choose plain
ArgParserorCommandRunnerbased on user-facing structure. - Load the relevant reference file above.
During implementation
- Centralize parser construction and canonical keys.
- Parse once.
- Use current typed APIs.
- Convert to typed application data.
- Validate semantics explicitly.
- Keep domain/application logic independent of
package:args. - Keep output and services testable.
- Preserve stable syntax and helpful usage.
During review
Inspect both parser semantics and architecture/platform fit. Test invalid and edge-case inputs, not only one happy path.
During optimization
Measure first. Move expensive I/O/dependency construction after parsing and command selection before considering parser micro-optimization.
Final Review Checklist
package:argsis actually appropriate for this executable.- Process/Dart-entrypoint arguments are real on the target platform.
- Arguments are parsed once at the outer boundary.
ArgResultsis converted to typed data promptly.- Canonical option keys are centralized.
- Typed accessors are used in new code.
- Syntax and semantic validation are separated.
- Mandatory single-option retrieval semantics are handled.
- Global vs command-local ownership is unambiguous.
- Positionals,
--, aliases, defaults, negation, and multi-options are tested where used. - CLI syntax/defaults are treated as compatibility contracts.
- Secrets are not casually exposed in argv/logs.
- Help and errors are actionable.
- Unexpected defects are not mislabeled as usage errors.
- Exit/cleanup behavior is safe for async work.
- Flutter Android/iOS/Web use platform-appropriate mechanisms.
- Desktop forwarding is verified when launch args are a feature.
--dart-define, environment variables, config files, URLs, and deep links are not conflated with argv.- Tests cover invalid/edge cases.
- Performance claims are measured or explicitly framed as engineering inference.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

