Skip to main content

amcli

Read, search, traverse, edit, validate and draw ArchiMate architecture models (.archimate files) from the command line with the `amcli` binary. Use when the user asks about an enterprise, solution or application architecture model; when they mention ArchiMate, Archi, coArchi, a .archimate file, application components, business processes, capabilities or an EA repository; or when a repository contains a *.archimate file. Also use for: finding which services depend on a component, tracing dependencies, assessing the blast radius of a change, listing what reads or writes a data object, adding or renaming elements and relationships, checking a model for rule violations, and producing a diagram. Prefer this over opening the model XML directly — these files run to megabytes, reading one wastes context, and hand-editing the XML corrupts models in ways Archi then refuses to open.

Source facts

Repository
arslanrakh/amcli
Last source activity
November 5, 2026 at 01:20
Detected SKILL.md language
English
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
6 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
amcli
description
Read, search, traverse, edit, validate and draw ArchiMate architecture models (.archimate files) from the command line with the `amcli` binary. Use when the user asks about an enterprise, solution or application architecture model; when they mention ArchiMate, Archi, coArchi, a .archimate file, application components, business processes, capabilities or an EA repository; or when a repository contains a *.archimate file. Also use for: finding which services depend on a component, tracing dependencies, assessing the blast radius of a change, listing what reads or writes a data object, adding or renaming elements and relationships, checking a model for rule violations, and producing a diagram. Prefer this over opening the model XML directly — these files run to megabytes, reading one wastes context, and hand-editing the XML corrupts models in ways Archi then refuses to open.
license
Apache-2.0
compatibility
Needs a shell and the `amcli` binary; if the binary is missing, the Setup section installs it and needs network for that one step. After that: no network, no daemon, and no Archi installation — amcli works directly on the model file. The one optional server is `amcli web`, a local read-only viewer that runs only while asked to and stops with Ctrl-C.
metadata
{"homepage":"https://github.com/arslanrakh/amcli","binary":"amcli","spec":"ArchiMate 3.2"}
# amcli — ArchiMate models from the command line A single binary that reads and edits ArchiMate model files directly. No GUI, no JVM, no daemon — and, when a person wants to *look* at the model, `amcli web` serves it read-only to their browser from the same binary. **Never read a `.archimate` file with Read or cat.** They run to megabytes of XML. Every question you have is one `amcli` command, and editing that XML by hand corrupts models. ## Setup Run this before anything else, **every session, without exception** — it installs amcli if it is missing, updates it if a newer release exists, and otherwise does nothing but print where the binary is. Never start work on a binary you have not tried to update this session; an old amcli lays views out differently and refuses flags this file describes: AMCLI=$(sh ~/.agents/skills/amcli/scripts/install.sh) $AMCLI --version The installer sits next to this file, which is normally `~/.agents/skills/amcli`, or `./.agents/skills/amcli` for a project install. It prints the absolute path of the binary on stdout and nothing else. **Use `$AMCLI` for the rest of the session.** A newly installed binary is usually not on the current shell's PATH yet, so plain `amcli` will still report "command not found" even though the install succeeded — that is the single most likely way this goes wrong. Running it every time is cheap and safe: it always asks GitHub for the newest release (one HTTP redirect); if that is what is installed it downloads nothing; if it is newer it fetches it, checked against the release's SHA256SUMS before it is unpacked and with no flag that skips the check; and only when there is no network at all does it keep whatever is installed, and it says so on stderr. **Native Windows PowerShell**, where there is no `sh`, use the PowerShell one instead. It follows the same contract: $AMCLI = & ~\.agents\skills\amcli\scripts\install.ps1 Either installer asks for nothing, never elevates, and never edits a shell config. If no prebuilt binary matches the platform it builds one with cargo on its own. Do not pipe either from a URL — they are already on disk. This skill is written for **amcli 0.17.5**. The installer always gives you the newest *release*, and this file ships from the repository's main branch, so for a short while after a change lands the binary can be one release behind what is described here. If a command or flag below is refused, the binary says so and names the fix; carry on with what the binary you have does support, and do not reinstall the skill to match the binary — that would only take you backwards. ## Finding the model amcli finds the model on its own: `-m PATH`, else `$AMCLI_MODEL`, else the nearest `*.archimate` walking up from the working directory. If several are found it exits 4 and lists them — pass `-m`, or `export AMCLI_MODEL=…` once for the session. It never guesses: `apply` with ten scratch copies beside you and the real model beside the batch file names that model in the hint rather than quietly applying to it, because a dry run that picks a model you did not name is a real run. ## The loop Start every architecture question here. Do not open source code first. amcli stats # how big is this thing, and of what amcli search <term> # find the concept, get its id amcli get <id-or-name> # what it is, and everything it touches amcli trace <id-or-name> -n 2 # the neighbourhood # only now read source code, and only the files the model pointed you at ## Flags mean one thing each -t concept type -r relationship type -f folder -D direction(out|in|both) -n depth -l limit -m model -F format -o output file Subjects are positional, never flags: amcli element add ApplicationComponent "Refund Service" -f /Application amcli relation add Serving "Refund Service" "Checkout Service" ## Output and token economy The default output is tab-separated records, one per line — cheap to read and easy to `cut -f2`. Counts, hints and a `# id<TAB>name<TAB>…` column header go to stderr, so read stderr to learn what the columns are. Add `-F json` only when you need nested structure, such as the relationship ids inside `get`. JSON is always the same shape — `{"ok":…,"data":[…],"meta":{…}}`, success or failure — so `.data[]` is the path whether or not `-q` is there; `-q` only quietens stderr. amcli query 'layer=Application' --count # ask "how many" FIRST, always amcli search auth -l 10 --fields id,name # project down amcli list --fields -documentation # or drop a field amcli query 'prop:reg-id=RG-14' --fields name,prop:reg-id # print what you filtered on **A field you can filter on is a field you can print.** Besides the columns a command prints by default, `--fields` takes `doc`, `layer`, `kind`, `deg` (`in + out`, the number the filter compares), `properties` (the whole list — in JSON the same array `get` carries, in text a count) and any `prop:KEY` — matched case-insensitively, as the filter matches it — and the value is appended as a column, empty where the concept has none. That is the route to one property: you do not need `-F json` to read it. It works on `view list` too. A field no record has is refused before any row is printed: exit 2 on a read, naming the columns the record does have; on a write, where the file has already changed, a warning ahead of the row instead, said whatever the flags. **JSON shapes.** A concept row from `list`, `search` or `query` has no `properties` key at all — `jq` prints `null` for a missing key — while `get` always carries `properties` as `[{"key","value"}]`; ask a list for `--fields …,properties` to get the same array, or `prop:KEY` for one value. A relationship reads the same wherever it turns up: `query 'kind=relation'` rows and the `relations` nested in `get` both carry `id`, `type`, `name`, `source`, `source_name`, `target` and `target_name` — `get` adds `direction` and `other_*` for the end that is not the one you asked about. **A capped answer says so on stderr, and `-q` cannot silence it.** Every list is cut to `-l` (50 by default) and prints `showing 50 of 83` when it cuts; `-l 0` gives all of them, and `--count` gives the true total without the rows. `-q` drops the header and the notes — never that line, and never the `"truncated"` field in the JSON envelope. If you are counting, count with `--count` or check the line. `--count` and `--dry-run` never write, on any command. Never run an unfiltered `list` on an unfamiliar model. Run `amcli stats` first. ## Addressing concepts id:id-5dde26f7… an id — always unambiguous, always prefer it id:5dde26f7 the hex without `id-`, or a prefix of it (4+ characters) "Payment API" an exact name ApplicationComponent:"Payment" a name qualified by type "*Payment*" a glob Ids in an Archi model are `id-` and thirty-two hex characters; `id:` takes the whole thing, the hex alone, or a prefix of it of at least four characters, so what you copy off a row resolves whether or not you kept the `id-`. A prefix two ids share is exit 4 with both listed. A miss says what ids look like in this model. Views take the same three forms. Filter expressions, quoted as one argument: amcli query 'type=ApplicationComponent and name~payment' amcli query 'prop:owner=team-a and not folder^=/Technology' amcli query 'layer=Application and deg>10' amcli query 'out:Access~Customer' # everything that accesses something matching amcli query 'kind=element and view=0' # in the model but on no diagram amcli query 'kind=element and view~"Refunds"' # what a view holds Operators: `=` exact · `~` contains · `^=` prefix · `=~` regex · `!=` · `>` `<` on `deg` and `view`. Fields: `id name type kind layer folder doc deg view prop:KEY in:RelType out:RelType`. Two of those are easy to get wrong: - `kind` is `element` or `relation`. Without it, filters like `layer!=none` return relationships mixed in with elements, and relationships have no name. A relationship row carries `source`, `source_name`, `target` and `target_name` after the usual columns, so `amcli query 'kind=relation'` and `amcli get` on a relationship both say what it joins — read that before deleting one. - `type` takes one ArchiMate type and accepts either spelling — `Triggering` and `TriggeringRelationship` are the same thing. So does `-t`. A type that does not exist is exit 2 with the model's own types listed, never an empty result. - `view` compares as a **number** against how many views a concept is drawn on (`view=0`, `view>1`), and as a **name** otherwise (`view~"Payments"`). The `views` column on every concept row is that same count. ## Exit codes — branch on these, do not parse messages 0 ok 2 usage 3 not found 4 ambiguous 5 invalid 6 conflict 7 io 8 unsupported On **3**, the response lists the nearest names — retry with one, do not run another search. On **4**, it lists candidates, each with a ready-to-paste `id:` selector. Never work around an ambiguity by guessing; re-run with the id. ## Graph questions amcli path "Web App" "Customer Database" # how are these connected? amcli impact id:5dde26f7 -D in # what breaks if this changes? amcli neighbors id:5dde26f7 -r Serving # only Serving relationships amcli ancestors "Payment API" # what composes or aggregates it amcli descendants "Payments Capability" # the composition tree amcli cycles # dependency cycles ## Editing amcli init "Model Name" -o model.archimate # a new, empty model amcli element add ApplicationComponent "Refund Service" --doc "…" amcli element rename id:c40a19b7 "Refunds Service" amcli relation add Access "Refunds Service" "Refund Record" --access rw amcli relation add Association "Refunds Service" "Ledger" --name "posts to" amcli element doc id:c40a19b7 "What it is for" amcli element move id:c40a19b7 -f /Application/Payments amcli element retype id:c40a19b7 TechnologyService amcli element merge "Old" --into "New" amcli prop set id:c40a19b7 owner team-payments amcli element delete id:c40a19b7 -y Never hand-write the XML skeleton for a new model — `amcli init` writes it with the nine folders Archi expects. `element retype` changes the type in place — same id, relationships and boxes, only the figure drawn changes — and is refused, listing them, when a relationship it has would break the matrix for the new type; fix those first, there is no force. `element merge` folds one element into another that means the same thing: relationships and boxes are repointed to the survivor, duplicates and would-be loops dropped, documentation appended and properties copied (`--drop-doc` leaves the words behind), and the merged element deleted. Every write is checked against the ArchiMate relationship matrix first and refused (exit 5) if the standard forbids it — and the refusal names what *is* permitted between those two types, so read it rather than guessing again. **A new relationship is drawn on every view that already shows both of its ends** — at the prompt and from a batch alike — because a view is a drawing of the model and what the model now says between two boxes belongs on the line between them. The row's `views` column counts the views it reached and a note names them; when one end is drawn somewhere but no view shows both, the note says so, and `amcli view add` of the missing end draws it there. `--no-draw` (`"no_draw":true` in a batch) adds it to the model only. `--name` puts a label on the line — Archi reads an Association as "related to" without one and "owns" with it — and `query` and `get` print it as `name`. Deleting refuses by default when it would take other things with it, and the refusal is the impact report. Add `-y` once you have read it. Use `--dry-run` when unsure. Use `--expect-checksum` when you read the model on an earlier turn and are writing now: CS=$(amcli info -F json | jq -r '.data[0].checksum') amcli element rename id:x "New" --expect-checksum "$CS" # exit 6 if it moved **For more than two edits, use one atomic batch rather than a sequence.** amcli apply - <<'EOF' {"op":"element.add","type":"ApplicationComponent","name":"Refund Service","ref":"r","if_absent":true} {"op":"element.add","type":"DataObject","name":"Refund Record","ref":"rec","if_absent":true} {"op":"relation.add","type":"Access","source":"ref:r","target":"ref:rec","access":"rw","if_absent":true} EOF `ref` names a line's result so a later line can point at it before its id exists. `if_absent` makes the batch safe to re-run. If any line fails, nothing is written and the file is byte-identical. View operations go in the same batch — `view.create`, `view.add` (with `into` to nest), `view.group`, `view.note`, `view.nest`, `view.sync`, `view.auto`, `view.layout`, `view.rename`, `view.move`, `view.delete`, same fields as the commands — so a view is built and laid out with the concepts it shows, in one write; `references/batch.md` has those and the folder ops, `folder.rename` and `folder.move` included. Deletes go in a batch too — `element.delete`, `relation.delete`, `prop.unset` — which is what lets a change that is really a *replacement* land as one write. Retyping a relationship is the common one, and the model never passes through a state where it says the wrong thing: amcli apply - <<'EOF' {"op":"relation.delete","target":"id:8f3c1a02","if_present":true} {"op":"relation.add","type":"Realization","source":"Payment API","target":"Payments","if_absent":true} EOF `if_present` is `if_absent` for deletes: with it, the second run of that batch finds nothing to do and writes a file identical to the one it read. **If the model is regenerated from batches you keep in the repository**, pass the same `--id-seed` every time (or set `$AMCLI_ID_SEED`). Ids are then derived from what they name instead of drawn at random, so rebuilding an unchanged model produces an unchanged file and the diff shows only what you meant to change. Without a seed every rebuild reissues every id and the whole file appears to change. Use one seed per model and do not change it afterwards. ## Before you finish any edit amcli validate Exit 5 means the model has errors. Each finding names a line in the file and carries a `fix` command. `amcli validate --fix` applies only the repairs that are derived rather than chosen — orphaned diagram objects and stale view mirrors — and never deletes anyone's modelling. ## Views and diagrams amcli view list # columns are named on stderr amcli view create "Refund Flow" -f /Views/Payments amcli view auto "Refund Flow" --from "Refund Service" -n 2 amcli view add "Refund Flow" "Fraud Check" # drawn *and* wired to what is there; a repeat adds nothing amcli view add "Refund Flow" "Fraud Rules" --into "Fraud Check" # nested inside it; no line, the nesting says it amcli view group "Refund Flow" "Card rails" # a titled box that stands for no concept amcli view note "Refund Flow" "Sandbox until go-live" --into "Card rails" amcli view nest "Refund Flow" "Fraud Rules" --into "Card rails" # move a box into another; no --into puts it back on top amcli view sync "Refund Flow" # draw what the model says between members and the view does not show amcli view style "Refund Flow" "Card rails" --fill "#eef5fc" --font-size 20 --font-style bold --border rectangle amcli view style "Refund Flow" "rel:id:8f3c1a02" --line "#2563a6" --label "P7 · bureaus" # every line drawing that relationship amcli view connect "Refund Flow" "Fraud Rules" "Acquirer" # one line, where sync would draw them all amcli view route "Refund Flow" id:<connection> --points 640,200 900,200 amcli view layout "Refund Flow" --relayout-all amcli view rename "Refund Flow" "Refunds" amcli view move "Refunds" -f /Views/Payments # re-file, id unchanged amcli view viewpoint "Refunds" application_cooperation # or "" to clear amcli view doc "Refunds" "What this drawing is for." # or "" to clear amcli view delete "Refunds" # removes the drawing, no concept amcli view render "Refunds" -o refund.svg amcli view render "Refunds" -o refund.png --scale 2 # a raster, from the extension amcli export views # the batch that rebuilds every view amcli export mermaid # a quick inline diagram for chat `view add` of a concept already on the view is a no-op with a note — the box stays where it is, the row says `added false`, and any relationship it can newly draw to what is there is drawn — so a rebuild batch that re-adds every member is re-runnable and never leaves a second box for one element. **A box inside a box is how Archi shows the relationship between them**, and it draws no line for it — by its default preferences, for every relationship type. amcli follows that rule exactly. `view add --into` draws the new box inside a concept already on the view, a group (by its name) or any object (by its id); the container grows to hold it, and no line is drawn between the two. A relationship whose two ends a view nests counts as *on* that view, so `views=0` does not report it, and `relation add` does not draw a line between a container and what it holds. `view nest` moves a box already on the view into another one — keeping its place on the canvas and removing any line between the two, exactly as dragging does in Archi — or, with no `--into`, back to the top, after which `view sync` draws the lines again. `view layout` lays each container's children out inside it, deepest first, and sizes every container to what it holds. `view group` puts a titled box that stands for no concept on the view, `view note` free text; both take `--into`, and `view note --object ID "…"` rewrites a note already there. **A poster — a drawing laid out by hand — is a batch too.** `view add` takes `--x --y --width --height` and `--again` (a second box for a concept the view already shows), `view group` and `view note` take sizes, `view style` sets what a person sets in Archi's properties on a box, a group, a note or a line (fill, line, width, font, text colour, alignment, position, border, opacity, a label expression, the icon), `view connect` draws one chosen relationship between two objects, and `view route` bends a line through canvas points. `export views` writes a view that carries any style as it was drawn — every bound, every line, every style and route, and no layout — so a poster is a reviewable, re-runnable file rather than something only Archi can edit; `references/batch.md` has the fields. A view name is unique: creating a second view with a name already in use is exit 6. Pass `--replace` to overwrite the old one, which is what makes a regenerate-everything script re-runnable: amcli view auto "Refund Flow" --from "Refund Service" --replace A replace redraws the view; it does not forget what the view said about itself. The viewpoint, the documentation and the properties of the view being replaced are kept unless the command sets them — `--viewpoint ""` clears the viewpoint, and a `view.doc` line later in the batch overwrites the documentation as it always did. A **viewpoint** narrows what a view is meant to say, and Archi shows it in the properties. `create` and `auto` take `--viewpoint` (`"viewpoint"` in a batch); `view viewpoint` sets or clears it on a drawing that already exists, which is what you want when a view grew past the one it was filed under. The id must be one of the 25 ArchiMate ones — a wrong one is exit 2 and the hint lists them all — and `""` clears it. Nothing is enforced by it: putting a concept the viewpoint does not cover on the view is a note on stderr, not a refusal. A view carries **documentation** exactly as a concept does, and Archi shows it in the properties. `view doc` writes it (`"op":"view.doc"` in a batch), `""` clears it, and `view list --fields name,doc` reads it back — a drawing is the one thing you hand to a person, so say on it what it is for. **Past about a dozen views, file them in folders.** `create` and `auto` take
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub