Skip to main content

The DartWay agent toolkit

The methodology of the framework, written for an agent instead of for a reader. Every project created by dartway create has it; dartway setup-ai installs it into a project you already have, and dartway update carries it forward. The source is toolkit/ in the monorepo; the installer is packages/dartway_cli/lib/src/toolkit_installer.dart.

dartway setup-ai --base-branch develop

Why the framework ships this at all​

DartWay is highly opinionated: less freedom in how to do things, more consistency and speed. The contract lives in the shared package and every call has exactly one handler with an access rule. A feature is a folder with exactly one public file. Styles live in the app's own UI kit and nowhere else. None of that is guessable from the API surface — an agent reading only pubspec.yaml writes correct Dart in the wrong shape, confidently, at speed, everywhere.

That is the failure worth naming. An agent that does not know the conventions does not produce compile errors you fix in a morning; it produces a second architecture inside the first one, faster than a person can review it. The toolkit exists so the agent writes in the conventions a person on the project would — and so the conventions checker agrees with it afterwards.

Toolkit and code evolve in the same repository and the same pull request: a change to a package's public API updates the affected skills with it. A skill that has fallen behind the API is worse than a missing one — the agent writes non-working code with full confidence.

What gets installed​

AGENTS.md # owner text + managed Codex connection block
CLAUDE.md # @AGENTS.md in a fresh project
.agents/
DARTWAY.md # shared managed policy
dartway-toolkit.json # revision and install choices
skills/dartway-*/SKILL.md # the one physical copy
.claude/
CLAUDE.md # @../.agents/DARTWAY.md
skills -> ../.agents/skills # Claude discovers the same skills
commands/ # shared skill wrappers
settings.json # Claude permissions, merged

create, setup-ai and update accept --agent codex|claude|both. The default is both; later installs preserve the recorded choice unless explicitly overridden. Skills always live in .agents/skills/, including for a Claude-only install. Switching to Codex removes the Claude symlink, command wrappers and managed connection; switching back recreates them. Custom skills and owner instructions are preserved. Codex permissions are not inferred from Claude settings.

toolkit/AGENTS.md is the policy source, installed with project tokens as .agents/DARTWAY.md. It is an index: the law table stays in the entry file; procedures are opened through the skill for the current task. Server and contract skills route to topic references instead of loading all procedures. An agreed task opens its layer skill directly; requirements analysis and planning are opened when needed. Finish and generation instructions load when those steps are reached.

Root AGENTS.md carries the project's rules and the managed Codex connection block. Fresh root CLAUDE.md contains only @AGENTS.md; managed .claude/CLAUDE.md imports the shared policy with @../.agents/DARTWAY.md. Claude resolves imports relative to the file containing them (Claude Code memory documentation). A Claude-only setup without a root AGENTS.md imports .agents/DARTWAY.md directly. Malformed connection blocks refuse installation before files are changed.

On update, managed dartway-* copies are replaced. A custom skill found only under .claude/skills/ moves into .agents/skills/; identical custom copies collapse. Different custom copies stop the install, name the conflicting skill and leave project files untouched. Resolve them yourself and run again. Unexpected skills-directory symlinks are refused rather than followed. The root instruction texts are never merged automatically: instructionsDuplicated is a warning when root CLAUDE.md contains prose while AGENTS.md exists. Move project rules into AGENTS.md and leave only @AGENTS.md in CLAUDE.md. See the migration note.

The first upgrade reads provenance from the old .claude/dartway-toolkit.json location and writes .agents/dartway-toolkit.json. Commit the shared skills, relative symlink and instruction files. Project findings remain in docs/dev_notes/.

Unattended executors​

The manifest's top-level interactive boolean defaults to true. Use --no-interactive with create, setup-ai or update to record false; later installs retain the choice unless explicitly overridden with --interactive. You can also edit .agents/dartway-toolkit.json directly.

With false, every managed step that needs a human answer instead puts its question, proposed text or action in the final report and stops that step. This includes framework issue/comment publication, finish suggestions, real-key/local-setup questions, and migration/backfill/destructive decisions. Independent authorized work continues. Silence never approves an action, and the executor never waits for an answer nobody can give.

The skills​

Requirements analysis and approach selection belong to the developer or executor, including Studio's specify and design steps. Start implementation from the issue or accepted specification and the affected layer skill. The managed index follows the layer order: contract → rows → generate and migrate → handlers → jobs/routes → app → tests and descriptions, skipping unaffected steps. Every task ends with dartway-finish.

SkillFor
dartway-runBringing the project up locally — the order of the steps and the real ports — and confirming it is alive
dartway-feature-scaffoldA feature end to end: its folder, its entry point and DwFeatureSpec, its layers
dartway-contractThe shared package: data objects, requests and commands, refusal codes, validation, generation
dartway-serverHandlers and the call context, rows and queries, auth hooks, jobs, routes
dartway-data-layerThe Flutter side of calls: requests, commands, actions, refusal texts
dartway-realtimeChannels, publishing, update actions
dartway-accessAccess rules, channel rules, roles, identities and keys
dartway-migrationsWriting, checking and applying migrations
dartway-uploadsFiles: upload purposes and their rules, the public and the private bucket, rows that store a file id
dartway-testingSix must-test risk classes, rare tests outside them through the gate, agent rules and the boundary that owns each test
dartway-navigationThe router: zones, route descriptors, guards
dartway-ui-kitThe kit as source inside the app, and the ban on raw styles outside it
dartway-on-devicePhone keyboard, focus, scroll and viewport behaviour on iOS and iOS web, with the known workarounds
dartway-finishBefore a commit or PR: fast gates and changed/mirrored tests locally when CI carries full suites, full local fallback otherwise; audit the diff and apply only what is confirmed
dartway-updatePlan an exact target, resolve the plugin, apply and verify notes, then record dispositions
dartway-push-deliveryServer-side push delivery
dartway-analyticsEvents tracked in the app and on the server, stored in the project's Postgres
dartway-mediaVideo and audio through the media plugin; the controls are the project's own kit widgets
dartway-documentationWhere descriptions live — DwFeatureSpec, doc comments, registries in code — and what docs/adr/ and docs/dev_notes/ must earn
dartway-framework-notesFiling a finding back to the framework as an issue: what must not travel, the labels, the marker a workaround leaves in the code

Two commands come with them. /commit writes one conventional-commit line in English and decides nothing local — whether commits carry a ticket belongs to the project's root instructions. /dartway-checkup reports the state of the whole project and what is worth taking into work next: it runs the project's gates first (dartway check, dartway generate --check, the analyzers, the tests), compares them with what CI actually runs, measures how far the project trails the framework, and only then spends reading on features — loading only the skills its findings point at, never the whole toolkit.

The names in the skills are the project's​

The toolkit's markdown carries tokens, and the installer replaces them in every installed .md file, so the skills talk about my_app_server, not about a placeholder:

TokenBecomes
__SHARED_PKG__The *_shared package
__SERVER_PKG__The *_server package
__FLUTTER_PKG__The *_flutter package
__FLUTTER_APP_FILE__The app's wiring file, <project>_app.dart
__BASE_BRANCH__--base-branch (default master)
__PROJECT_LANGUAGE__--language (default English)
__NOTES_TRACKER__--notes-tracker (default dartway/dartway), or none

The packages are detected by directory suffix at the project root on every run; exactly one *_shared, one *_server and one *_flutter are required. A token nothing fills stops the install before a file is touched: the installer reads the toolkit first, and a token this CLI does not know, or one it would fill with nothing, is named with its file — a toolkit from another framework revision than the CLI, rather than a skill that tells the agent about /lib/src/. The three flag settings are recorded in .agents/dartway-toolkit.json and replayed by the next install unless a flag names another value — see The CLI.

Managed files, project files, and the one in between​

Managed files are the toolkit's, and every install removes them and copies them again: .agents/DARTWAY.md, .claude/CLAUDE.md, every skill directory named dartway-*, and the commit.md and dartway-checkup.md commands (a retired command on the installer's list is removed the same way). Custom skills are preserved in .agents/skills/; custom Claude commands stay in .claude/commands/. Migration may move a custom skill from the old Claude directory into the shared root.

So do not edit a dartway-* skill in place: the next install drops the change. To customize, copy the skill under another name and edit the copy. The source of truth is toolkit/ in the monorepo, and there is no reverse sync. Rules a project adds of its own belong in root AGENTS.md or its own skills.

.claude/settings.json is a toolkit default the project extends, so it is merged rather than overwritten or skipped. It pre-approves this stack's build, test and run commands — dart pub get, the analyzers, the test runners, dartway, docker compose up — so a first run is not a queue of permission prompts, and it denies reading deploy/secrets.yaml, turning a rule the skills state into one the harness enforces. Nothing destructive is on the allow list. On an install, entries the toolkit has and the project lacks are added, a value the project holds is never replaced, and every added entry is printed — the one cost of merging is an entry a project removed on purpose coming back, and printing makes that visible in the same run. A file that is not a JSON object is left as it is and reported.

docs/dev_notes/ holds the project's own findings, one committed file per finding. It is tracked, not git-ignored — a finding travels out in the pull request that carries it and survives a git worktree remove. README.md there is the toolkit's and is refreshed on every install; _coverage.md is the project's record of what /dartway-checkup has read, created once and never touched again.

.agents/dartway-toolkit.json records where the install came from — the repository or local path, the channel, the commit, the CLI version — and the settings. It records provenance, not content: a list of installed files or their hashes would be a second copy of the files, and copies drift.

Commit .agents/, selected .claude/ files, root instruction blocks and docs/dev_notes/ after every install: a clone comes with the skills in place, and the history records which version of the methodology a piece of code was written under.

Findings about the framework go back to the framework​

A rule that did not catch a mistake, two skills that disagree, an API the app had to work around — none of that can be fixed in the installed copy, and all of it is worth keeping: the rules are only ever proven wrong by real code. So a finding about the framework is filed as an issue in the repository --notes-tracker names, which defaults to the framework's own tracker, dartway/dartway. A finding about the project itself goes to docs/dev_notes/, or to the knownIssues of the feature it belongs to.

The default is deliberate. A project that never decided where its findings should go is a project whose findings stay on one laptop, and making the decision a precondition would reproduce exactly that in every project that skipped it. --notes-tracker owner/repo sends them to another repository; --notes-tracker none files nothing outside the project — the finding is written into docs/dev_notes/ like any other.

Keeping it current​

  • dartway setup-ai — the first install, or a re-install on the same channel.
  • dartway update --plan — a read-only exact-target plan and plugin resolution preflight. update --target <sha> installs that committed toolkit and resolvable plugin configuration. Migration notes stay unconfirmed until explicitly verified as applied or not applicable in .dartway/migrations.json; toolkit installation and dependency locks do not complete them. The dartway-update skill carries the plan through project edits and verification.
  • --local-repo <checkout> (or DARTWAY_MONOREPO_DIR) — install from a local monorepo checkout instead of a channel, for working on the framework and a project side by side. It records no channel. A CLI activated from a checkout uses that checkout when no channel is chosen.

A plain re-run that would move a project to another channel is refused and asks for the channel by name. The details of both commands are in The CLI.

What the toolkit does not do​

The toolkit supplies DartWay knowledge and verification procedures; the developer or executor owns the working method. dartway-finish shows what it would change and applies only the confirmed part.