Skip to content

11 AI Agents

Remy van Duijkeren edited this page Aug 22, 2026 · 2 revisions

AI Agents

AI agents (Claude Code, GitHub Copilot Workspace, CI scripts) can drive Flowline without parsing free-form output. Two contracts make that work: structured exit codes, and error messages that include the corrective action. There's also an agent plugin for Claude Code and Codex that makes Flowline commands available without extra prompting.

Claude Code / Codex plugin

Install Flowline as an agent plugin so Claude Code or Codex already knows how to drive it before you've even cloned a project:

# Claude Code
/plugin marketplace add RemyDuijkeren/Flowline
/plugin install flowline@flowline

# Codex
codex plugin marketplace add RemyDuijkeren/Flowline
codex plugin add flowline@flowline

Ships five skills. Each carries its own trigger conditions, so the agent loads the relevant one without being told which. Edit a plugin class and the plugin-authoring skill applies itself.

  • flowline covers the core loop this page documents: detect a project, edit code with attributes/annotations, push --dry-runpushsyncdeploy, branch on exit codes. Triggers on a .flowline file at the repo root, or on any mention of Dataverse plugins, web resources, Custom APIs, or solution deploy.
  • flowline-plugins covers authoring plugin steps and Custom APIs: the class-naming convention that determines message, stage, and processing mode, the [Step] / [Filter] / [PreImage] / [PostImage] / [CustomApi] attributes, and how registrations are verified. Triggers when writing, renaming, splitting, or reviewing a C# plugin class in a repo referencing Flowline.Attributes, when converting a Power Automate flow or workflow into a plugin, or when push reports a step it could not parse or that landed on the wrong message or stage. See Push Plugins and Custom APIs.
  • flowline-webresources covers authoring web resources: how a file under dist/ becomes a Dataverse web resource name, the IIFE global a form event handler is registered against, and the // flowline:onload / onsave / onchange / tabstatechange / onreadystatecomplete / depends annotations that wire forms and dependencies without a Maker Portal visit. Triggers when writing or reviewing a script, image, or HTML page under WebResources/, when a handler is not firing on a form, or when push reports a malformed annotation, a form it cannot find, or a name collision. See Push WebResources.
  • flowline-generate covers early-bound types: whether they are needed at all, where the generated models land, which settings persist to .flowline, and the three generators (pac, xrmcontext, xrmcontext3). Triggers when a plugin references a table or column that will not compile, when Models/ is missing or stale after a schema change, when choosing between late-bound and early-bound, or when output lands in an unexpected folder or namespace. See Generate Early-Bound Types.
  • flowline-migration detects an existing spkl, Daxif, PACX, or ALM Accelerator project unprompted (a spkl.json, a Daxif _Config.fsx or *.daxif, a .pacxproj, or an Azure DevOps pipeline using Power Platform Build Tools, with no .flowline yet), walks you through the matching migration guide (spkl, Daxif, ALM Accelerator, PACX), then verifies the result by actually running flowline push --dry-run / sync instead of trusting that the steps were followed.

Exit codes

Exit codes are a stable public API and don't change across versions. Renumbering would be a breaking change and requires a release note.

Codes 3, 4, and 130 follow de facto CLI conventions (curl, git, rsync). Codes 10 to 21 are Flowline-specific.

Code Name Meaning Corrective action
0 Success Command completed None
1 GeneralError Unexpected/unhandled error Check error output
3 NotFound Solution not in Dataverse or repo Verify solution name matches .flowline
4 NotAuthenticated No PAC auth profile Run: pac auth create --environment <url>
10 ConnectionFailed Dataverse environment unreachable Check environment URL in .flowline
11 ConfigInvalid .flowline missing or malformed Verify .flowline exists and is valid
12 DirtyWorkingDirectory Uncommitted git changes block the operation git commit or git stash first
13 BuildFailed dotnet build or PAC pack failed Fix errors in Plugins/ and retry
14 VersionConflict Target environment has a newer solution version Add the --force <specifier> the error names
15 ValidationFailed Drift detected, missing dependencies, invalid --force value, or schema mismatch Run flowline sync first; check error output. An invalid --force value lists the ones that are valid for that command
16 Timeout A Dataverse request got no response, or the PAC CLI 60-minute limit was exceeded Re-run the same command. The write may already have landed, and the reconciling commands converge on a re-run; check environment health if it repeats
17 ForceRequired Destructive operation requires explicit confirmation Add the --force <specifier> the message names, e.g. --force config, --force recreate-assembly
18 PartialSuccess Deploy completed but orphan cleanup failed for some components Remove the named items manually via maker portal
19 Inconclusive A check couldn't run to completion: drift's empty-input guard skipped the comparison, or a deploy verification step couldn't finish (e.g. a locked directory or a Dataverse query fault) Not a pass/fail signal. Investigate the printed reason before trusting the result
20 WriteTargetOccupied A file already occupies a path the command would write to: scaffold meeting an existing template file, or --output pointing at a file rather than a folder Distinct from 11: nothing is missing or malformed, something valid is in the way. Move the named file aside, or run the command somewhere else
21 AssemblyNotRegistered Deploy completed but a plug-in package holds an assembly with no registration in the target, or one registered with no plugin types Create the pluginassembly record under that package (sandbox isolation, matching version/culture/public key token), then deploy again so the content write populates its plugin types. This repeats every deploy until that record exists
130 Cancelled Ctrl+C / SIGINT, or deploy's first-import confirmation declined interactively For the confirmation case: re-run with --force first-import to proceed non-interactively

Codes 2 and 5 are intentionally unused.

Error messages

Every error message states what happened and what to do next. For the four most actionable codes, the corrective command is included verbatim in the message, so agents can extract the fix directly without consulting a lookup table:

Code Message includes
4 (NotAuthenticated) run: pac auth create --environment <url>
12 (DirtyWorkingDirectory) Commit or stash changes first
14 (VersionConflict) Add --force <specifier> to overwrite
17 (ForceRequired) Use --force <specifier> to proceed, and the specifier named is always valid for the command that raised it

Command selection

Each command description follows the what + when + what-changes-after pattern:

Command What it does When to run What changes after
clone Initialize project from an existing Dataverse solution One-time setup per solution that already exists Folder structure, unpacked XML, Plugins and WebResources projects, AGENTS.md, CLAUDE.md, DATAVERSE_CONTEXT.md
init Create publisher + empty unmanaged solution in DEV, then scaffold One-time setup when the solution does not exist in Dataverse yet Publisher and solution created in DEV; then everything clone produces; DEV URL saved to .flowline
push Register plugins and web resources to DEV After plugin or web resource changes DEV reflects current source; no pack/import involved
sync Export from DEV, bump version, unpack to XML After testing changes in DEV Solution/src/ updated; build version bumped; DATAVERSE_CONTEXT.md regenerated
deploy Pack and import into target environment After sync + commit Target environment updated with current solution version
provision Create environment by copying from PROD One-time setup for new environments Environment URL saved to .flowline
generate Generate early-bound C# types from solution After adding or modifying entities or custom APIs Plugins/Models/ overwritten with generated .cs files
drift Report what deploy's orphan cleanup would delete Before deploy, or as a standalone check on prod/test Read-only, nothing changes
scaffold Write a project template (webresources) into the current folder Adding web resources to a repo that has none WebResources/ project written where you are standing, and added to the nearest solution file (searched upward to the .flowline/.git root) when there is one. --output moves the folder, --name names it. No Dataverse call
status Show environment, auth, and git state Before running commands; when troubleshooting Read-only, nothing changes
sln add Add a .cdsproj to the solution file A repo assembled by hand or migrated off another tool Solution file updated, found by searching upward to the .flowline/.git root, same rule as scaffold. No Dataverse call

Daily dev loop

dotnet build                       # build plugin assembly
flowline push                      # register DLL + web resources in DEV
flowline push --dry-run            # preview changes before touching Dataverse
# make changes in the maker portal if needed
flowline sync                      # pull solution state from DEV, unpack to repo
git add . && git commit -m "..."   # commit the unpacked XML diff
flowline deploy test               # promote to TEST
flowline deploy prod               # promote to PROD

Rules

  • Use Flowline, not pac solution directly. Flowline wraps PAC commands with correct sequencing, version bumping, and cleanup.
  • Pick init vs clone by whether the solution already exists in Dataverse. init creates one and refuses a unique name that's already taken; clone adopts an existing one and never creates. Guessing wrong costs a round-trip, not data.
  • init runs against Sandbox and Developer environments only. It's an allow-list, so Production, Trial, Default and unknown types are all refused with exit 15. It also never creates a pac auth profile; if none matches the target it errors naming pac auth create.
  • init never prompts in a non-interactive run. Pass <name>, --dev <url>, and --publisher-prefix <prefix>. Each missing one fails naming the flag rather than hanging on a prompt.
  • sync requires a clean working directory. Exits 12 if there are uncommitted changes in Solution/src/. Commit or stash first.
  • deploy packs from source, not from a previous export. If local changes exist that haven't been synced to DEV, deploy would overwrite them. Flowline detects this drift and exits 15. Run sync first.
  • --force <specifier> is required for destructive operations in non-interactive mode. --force always takes a value naming the exact hazard being approved (e.g. --force dirty, --force config). A bare --force is a parse error, and an unrecognized value fails listing the ones valid for that command. Without it, Flowline exits 17 rather than asking for confirmation, which is safe for scripted use. See 04-Command-Reference for the per-command --force vocabulary.
  • status is always safe to run. Read-only; use it to verify connectivity and auth before running other commands.

Project structure

.flowline                              ← environment URLs + solution config
docs/DATAVERSE_CONTEXT.md              ← schema snapshot for AI agents (auto-generated)
Solution/<SolutionName>.cdsproj        ← solution metadata
Solution/src/                          ← unpacked solution XML (git-diffable)
Plugins/<SolutionName>.Plugins.csproj  ← plugin source, decorated with [Step] attributes
WebResources/<SolutionName>.WebResources.csproj  ← web resource build project
WebResources/dist/                     ← web resource files synced to Dataverse by push
AGENTS.md                              ← scaffolded by flowline clone / init (this file)
CLAUDE.md                              ← scaffolded by flowline clone / init (`@AGENTS.md` import)

Need a genuine second solution in one repo? Two documented patterns: a separate repo per solution (default), or a nested solutions/<Name>/ folder inside one repo containing multiple independent, self-contained Flowline projects (each with its own .flowline, Solution/, Plugins/, WebResources/). This works via Flowline's existing upward .flowline discovery, with no code changes required.

AGENTS.md scaffolding

flowline clone writes an AGENTS.md file at the repo root with the solution name substituted throughout. It includes:

  • The daily dev loop for this specific solution
  • Project structure with actual paths
  • Exit code reference table
  • Rules for this project

If AGENTS.md already exists, Flowline skips the write and logs an info message. It will not overwrite a customized file.

GitHub Copilot and Codex load AGENTS.md automatically on project open. Claude Code does not read AGENTS.md directly, it only auto-loads CLAUDE.md, so flowline clone also scaffolds a one-line CLAUDE.md containing @AGENTS.md, which Claude Code resolves as an import. Same skip-if-exists behavior applies. Keep AGENTS.md accurate as the project evolves.

Dataverse schema context

After every successful flowline clone or flowline sync, Flowline writes docs/DATAVERSE_CONTEXT.md, a curated markdown snapshot of the solution schema optimised for AI token efficiency.

What it contains

Section Content
Solution Display name, unique name, version, publisher prefix
Entities Logical name, display name, EntitySetName, ownership type
Attributes Logical name, type, required level, description, custom flag
Option sets Inline value → label mapping for picklist and boolean fields
Forms Condensed tab → section → field list (hidden controls excluded)
Views Column list and filter summary (no verbatim FetchXML)
Workflows Display name, activation state, trigger entity
Plugin steps Message, entity, stage (pre/post-operation), mode (sync/async), class name
Connection references Display name, connector ID

Sections with no content are omitted. No GUIDs appear in the output.

AGENTS.md integration

flowline clone seeds AGENTS.md with a "Dataverse schema context" section at the end:

## Dataverse schema context
- [ContosoSales](docs/DATAVERSE_CONTEXT.md)

@docs/DATAVERSE_CONTEXT.md

The @ import causes Codex and GitHub Copilot to load the schema automatically on every request from AGENTS.md, and Claude Code to load it via the CLAUDE.mdAGENTS.md import chain.

After every flowline sync, Flowline checks AGENTS.md and appends the import and link if missing (self-healing). The entry is never duplicated on repeated runs.

If AGENTS.md does not exist when sync runs, Flowline emits a warning and skips the mutation. Run flowline clone to scaffold it.

Clone this wiki locally