Skip to content

Workflows in Git

A workspace’s workflows can live in a Git repository: the workflow designer pushes them there and pulls them back, and the same files come as a ZIP from Export (Export, import and Git). This page is for the people who keep that repository: what is in it, how to check the scripts on your own machine and in CI, and how a branch comes back into the workspace. Whatever comes back is a draft; publishing stays a person’s click in the app.

An export or a push writes:

CLAUDE.md instructions for AI agents (also AGENTS.md and the skill below)
AGENTS.md
.claude/skills/acriva-workflows/SKILL.md
workflows/
invoice-approval/ one folder per workflow, named by its key
workflow.yaml the steps, the trigger, the settings and the fields it declares
scripts/route.ts the scripts of its script steps
types/acriva.d.ts the SDK's declarations (the version the workflow pins)
types/tenant.d.ts the workspace's types this workflow uses
types/route.step.d.ts per script step: the fields its script reads and sets
  • workflow.yaml follows the published JSON Schema: keys in a stable order, step names as IDs, no IDs of the workspace, no timestamps and no secrets. People, roles, document types, tags, Akten, file types and cost centers are named by key, email, name or number, and an import maps them to the importing workspace’s objects.
  • types/ is written for editors and CI. Don’t edit it: the server checks scripts against its own declarations, and the next export writes the folder again.
  • fixtures/<name>.json (optional, yours) holds synthetic cases for the CLI’s acriva workflows test.
  • Your own files belong next to workflows/, at the root: a README.md, the CI configuration, the check script below.

What comes back, and from where:

  • A pull reads only workflows/<key>/workflow.yaml and workflows/<key>/scripts/<name>.ts of the commit and ignores every other file. A symbolic link or a submodule under workflows/ refuses the pull.
  • A ZIP import reads the same files and ignores every file outside workflows/, so a repository zipped as it is imports. Under workflows/ it refuses any file a package doesn’t hold, and anywhere in the ZIP a symbolic link, an encrypted entry or an unsafe path. At the root it refuses what an AI agent’s tool would run from a checkout: a .mcp.json, anything in .claude/ other than the skill acriva-workflows, and a CLAUDE.md spelled in another case.
  • A package holds at most 54 workflows and 500 entries, its folders included, and a ZIP is at most 10 MB. The ignored files count towards both: for a larger repository, zip workflows/ alone, for example git archive --format=zip -o workflows.zip HEAD workflows.

Each workflow has its own types/: its tenant.d.ts names only what that workflow uses, and each script step’s <script>.step.d.ts types ctx.document.fields with the step’s inputs and ctx.setField with the fields it may set, as the app’s check does. Type-check one script at a time with TypeScript, with these files and the SDK’s import mapped to the workflow’s types/acriva.d.ts. This script at the repository’s root does it for every script:

check-scripts.sh
#!/bin/sh
# Type-checks each script against its workflow's types/ and its step's declarations (strict, no emit).
set -eu
config="$(mktemp -d)/tsconfig.json"
status=0
for script in "$PWD"/workflows/*/scripts/*.ts; do
[ -f "$script" ] || continue
dir="${script%/scripts/*}"
step="$dir/types/$(basename "$script" .ts).step.d.ts"
cat > "$config" <<JSON
{
"compilerOptions": {
"strict": true, "noEmit": true, "target": "ES2022", "lib": ["ES2022"],
"module": "ESNext", "moduleResolution": "Bundler", "types": [],
"paths": { "@acriva/workflow-sdk": ["$dir/types/acriva.d.ts"] }
},
"files": ["$script", "$dir/types/acriva.d.ts", "$dir/types/tenant.d.ts", "$step"]
}
JSON
echo "checking ${script#"$PWD"/}"
npx --yes --package typescript@6.0.3 tsc --project "$config" || status=1
done
exit $status

Run it with sh check-scripts.sh (Node.js 20 or later). An editor such as VS Code shows the same errors with the same settings in a tsconfig.json of the script’s own; keep that file out of a ZIP you import.

The server’s check goes further than TypeScript: it also lints the scripts with Acriva’s rules (no fetch, no timers, only declared effects), with ACR-S codes. With an API key, the CLI @acriva/cli runs that check from the command line: acriva workflows validate.

The same two checks in CI catch a broken script or a workflow.yaml the format doesn’t allow before anyone pulls the branch. For GitHub Actions:

.github/workflows/workflows.yml
name: workflows
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Type-check the scripts
run: sh check-scripts.sh
- name: Check workflow.yaml against the JSON Schema
run: pipx run --spec check-jsonschema==0.33.0 check-jsonschema --schemafile https://docs.acriva.de/schemas/workflow.schema.json workflows/*/workflow.yaml

In another CI service, run the same two commands in a job with an image that has Node.js and Python. The schema checks the file’s form; references to the workspace (does the role exist, is the tag there) are checked when the workflow is imported, and the publish checks the whole workflow again.

In the workflow designer, the Git view pulls a branch, a tag or a commit:

  1. Open a workflow in the designer and select the chip Git: with the branch in the toolbar (or Git in the full screen script editor’s side bar).
  2. Under Pull, choose the Kind of reference (Branch, Tag or Commit), enter its name or SHA and select Pull as draft.
  3. When a reference of the pulled workflows doesn’t exist in the workspace, Continue import opens the import: map each one to an object of the workspace under Map references, or remove it.
  4. Compare shows each workflow’s workflow.yaml and scripts, left your current draft, right the pulled files. Use as draft replaces the drafts.
  5. Check the draft in the designer and select Publish. Nothing is published before that.

A pull of a commit by its SHA needs a remote that allows it; otherwise pull a branch or a tag. A workspace can start 10 transfers in 10 minutes, one at a time. The same pull is POST /api/v1/t/{tenant}/workflows/git-remote/pull with {"ref": "feature/skonto", "kind": "Branch"} (API reference), and acriva workflows push imports a local checkout as drafts without a remote.